grml...
[seabios.git] / src / vgahooks.c
1 // Hooks for via vgabios calls into main bios.
2 //
3 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
4 //
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
6
7 #include "bregs.h" // set_code_invalid
8 #include "biosvar.h" // GET_GLOBAL
9 #include "pci.h" // pci_find_device
10 #include "pci_regs.h" // PCI_VENDOR_ID
11 #include "pci_ids.h" // PCI_VENDOR_ID_VIA
12 #include "util.h" // handle_155f
13 #include "config.h" // CONFIG_*
14
15 #define VH_VIA 1
16 #define VH_INTEL 2
17
18 int VGAHookHandlerType VAR16VISIBLE;
19
20 static void
21 handle_155fXX(struct bregs *regs)
22 {
23     set_code_unimplemented(regs, RET_EUNSUPPORTED);
24 }
25
26
27 /****************************************************************
28  * Via hooks
29  ****************************************************************/
30
31 int ViaFBsize VAR16VISIBLE, ViaRamSpeed VAR16VISIBLE;
32
33 static void
34 via_155f01(struct bregs *regs)
35 {
36     regs->eax = 0x5f;
37     regs->cl = 2; // panel type =  2 = 1024 * 768
38     set_success(regs);
39     dprintf(1, "Warning: VGA panel type is hardcoded\n");
40 }
41
42 static void
43 via_155f02(struct bregs *regs)
44 {
45     regs->eax = 0x5f;
46     regs->bx = 2;
47     regs->cx = 0x401;  // PAL + crt only
48     regs->dx = 0;  // TV Layout - default
49     set_success(regs);
50     dprintf(1, "Warning: VGA TV/CRT output type is hardcoded\n");
51 }
52
53 static void
54 via_155f18(struct bregs *regs)
55 {
56     int fbsize = GET_GLOBAL(ViaFBsize), ramspeed = GET_GLOBAL(ViaRamSpeed);
57     if (fbsize < 0 || ramspeed < 0) {
58         set_code_invalid(regs, RET_EUNSUPPORTED);
59         return;
60     }
61     regs->eax = 0x5f;
62     regs->ebx = 0x500 | (ramspeed << 4) | fbsize;
63     regs->ecx = 0x060;
64     set_success(regs);
65 }
66
67 static void
68 via_155f19(struct bregs *regs)
69 {
70     set_invalid_silent(regs);
71 }
72
73 static void
74 via_155f(struct bregs *regs)
75 {
76     switch (regs->al) {
77     case 0x01: via_155f01(regs); break;
78     case 0x02: via_155f02(regs); break;
79     case 0x18: via_155f18(regs); break;
80     case 0x19: via_155f19(regs); break;
81     default:   handle_155fXX(regs); break;
82     }
83 }
84
85 static int
86 getFBSize(struct pci_device *pci)
87 {
88     /* FB config */
89     u8 reg = pci_config_readb(pci->bdf, 0xa1);
90
91     /* GFX disabled ? */
92     if (!(reg & 0x80))
93         return -1;
94
95     static u8 mem_power[] = {0, 3, 4, 5, 6, 7, 8, 9};
96     return mem_power[(reg >> 4) & 0x7];
97 }
98
99 static int
100 getViaRamSpeed(struct pci_device *pci)
101 {
102     return (pci_config_readb(pci->bdf, 0x90) & 0x07) + 3;
103 }
104
105 static int
106 getAMDRamSpeed(void)
107 {
108     struct pci_device *pci = pci_find_device(PCI_VENDOR_ID_AMD
109                                              , PCI_DEVICE_ID_AMD_K8_NB_MEMCTL);
110     if (!pci)
111         return -1;
112
113     /* mem clk 0 = DDR2 400 */
114     return (pci_config_readb(pci->bdf, 0x94) & 0x7) + 6;
115 }
116
117 /* int 0x15 - 5f18
118
119    ECX = unknown/dont care
120    EBX[3..0] Frame Buffer Size 2^N MiB
121    EBX[7..4] Memory speed:
122        0: SDR  66Mhz
123        1: SDR 100Mhz
124        2: SDR 133Mhz
125        3: DDR 100Mhz (PC1600 or DDR200)
126        4: DDR 133Mhz (PC2100 or DDR266)
127        5: DDR 166Mhz (PC2700 or DDR333)
128        6: DDR 200Mhz (PC3200 or DDR400)
129        7: DDR2 133Mhz (DDR2 533)
130        8: DDR2 166Mhz (DDR2 667)
131        9: DDR2 200Mhz (DDR2 800)
132        A: DDR2 233Mhz (DDR2 1066)
133        B: and above: Unknown
134    EBX[?..8] Total memory size?
135    EAX = 0x5f for success
136 */
137
138 #define PCI_DEVICE_ID_VIA_K8M890CE_3    0x3336
139 #define PCI_DEVICE_ID_VIA_VX855_MEMCTRL 0x3409
140
141 static void
142 via_setup(struct pci_device *pci)
143 {
144     VGAHookHandlerType = VH_VIA;
145
146     struct pci_device *d = pci_find_device(PCI_VENDOR_ID_VIA
147                                            , PCI_DEVICE_ID_VIA_K8M890CE_3);
148     if (d) {
149         ViaFBsize = getFBSize(d);
150         ViaRamSpeed = getAMDRamSpeed();
151         return;
152     }
153     d = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855_MEMCTRL);
154     if (d) {
155         ViaFBsize = getFBSize(d);
156         ViaRamSpeed = getViaRamSpeed(d);
157         return;
158     }
159
160     dprintf(1, "Warning: VGA memory size and speed is hardcoded\n");
161     ViaFBsize = 5; // 32M frame buffer
162     ViaRamSpeed = 4; // MCLK = DDR266
163 }
164
165
166 /****************************************************************
167  * Intel VGA hooks
168  ****************************************************************/
169
170 u8 IntelDisplayType VAR16VISIBLE, IntelDisplayId VAR16VISIBLE;
171
172 static void
173 intel_155f35(struct bregs *regs)
174 {
175     regs->ax = 0x005f;
176     regs->cl = GET_GLOBAL(IntelDisplayType);
177     set_success(regs);
178 }
179
180 static void
181 intel_155f40(struct bregs *regs)
182 {
183     regs->ax = 0x005f;
184     regs->cl = GET_GLOBAL(IntelDisplayId);
185     set_success(regs);
186 }
187
188 static void
189 intel_155f50(struct bregs *regs)
190 {
191     /* Mandatory hook on some Dell laptops */
192     regs->ax = 0x005f;
193     set_success(regs);
194 }
195
196 static void
197 intel_155f(struct bregs *regs)
198 {
199     switch (regs->al) {
200     case 0x35: intel_155f35(regs); break;
201     case 0x40: intel_155f40(regs); break;
202     case 0x50: intel_155f50(regs); break;
203     default:   handle_155fXX(regs); break;
204     }
205 }
206
207 #define BOOT_DISPLAY_DEFAULT    (0)
208 #define BOOT_DISPLAY_CRT        (1 << 0)
209 #define BOOT_DISPLAY_TV         (1 << 1)
210 #define BOOT_DISPLAY_EFP        (1 << 2)
211 #define BOOT_DISPLAY_LCD        (1 << 3)
212 #define BOOT_DISPLAY_CRT2       (1 << 4)
213 #define BOOT_DISPLAY_TV2        (1 << 5)
214 #define BOOT_DISPLAY_EFP2       (1 << 6)
215 #define BOOT_DISPLAY_LCD2       (1 << 7)
216
217 static void
218 intel_setup(struct pci_device *pci)
219 {
220     VGAHookHandlerType = VH_INTEL;
221
222     IntelDisplayType = BOOT_DISPLAY_DEFAULT;
223     IntelDisplayId = 3;
224 }
225
226 static void
227 roda_setup(struct pci_device *pci)
228 {
229     VGAHookHandlerType = VH_INTEL;
230     // IntelDisplayType = BOOT_DISPLAY_DEFAULT;
231     IntelDisplayType = BOOT_DISPLAY_LCD;
232     // IntelDisplayId = inb(0x60f) & 0x0f; // Correct according to Crete
233     IntelDisplayId = 3; // Correct according to empirical studies
234 }
235
236 static void
237 kontron_setup(struct pci_device *pci)
238 {
239     VGAHookHandlerType = VH_INTEL;
240     IntelDisplayType = BOOT_DISPLAY_CRT;
241     IntelDisplayId = 3;
242 }
243
244 static void
245 getac_setup(struct pci_device *pci)
246 {
247 }
248
249
250 /****************************************************************
251  * Entry and setup
252  ****************************************************************/
253
254 // Main 16bit entry point
255 void
256 handle_155f(struct bregs *regs)
257 {
258     if (!CONFIG_VGAHOOKS) {
259         handle_155fXX(regs);
260         return;
261     }
262
263     int htype = GET_GLOBAL(VGAHookHandlerType);
264     switch (htype) {
265     case VH_VIA:   via_155f(regs); break;
266     case VH_INTEL: intel_155f(regs); break;
267     default:       handle_155fXX(regs); break;
268     }
269 }
270
271 // Setup
272 void
273 vgahook_setup(struct pci_device *pci)
274 {
275     if (!CONFIG_VGAHOOKS)
276         return;
277
278     if (strcmp(CBvendor, "KONTRON") == 0 && strcmp(CBpart, "986LCD-M") == 0)
279         kontron_setup(pci);
280     else if (strcmp(CBvendor, "GETAC") == 0 && strcmp(CBpart, "P470") == 0)
281         getac_setup(pci);
282     else if (strcmp(CBvendor, "RODA") == 0 && strcmp(CBpart, "RK886EX") == 0)
283         roda_setup(pci);
284     else if (pci->vendor == PCI_VENDOR_ID_VIA)
285         via_setup(pci);
286     else if (pci->vendor == PCI_VENDOR_ID_INTEL)
287         intel_setup(pci);
288 }