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 "biosvar.h" // GET_GLOBAL
8 #include "bregs.h" // set_code_invalid
9 #include "config.h" // CONFIG_*
10 #include "hw/pci.h" // pci_config_readb
11 #include "hw/pcidevice.h" // pci_find_device
12 #include "hw/pci_ids.h" // PCI_VENDOR_ID_VIA
13 #include "hw/pci_regs.h" // PCI_VENDOR_ID
14 #include "output.h" // dprintf
15 #include "string.h" // strcmp
16 #include "util.h" // handle_155f, handle_157f
17
18 #define VH_VIA 1
19 #define VH_INTEL 2
20 #define VH_SMI 3
21
22 int VGAHookHandlerType VARFSEG;
23
24 static void
handle_155fXX(struct bregs * regs)25 handle_155fXX(struct bregs *regs)
26 {
27 set_code_unimplemented(regs, RET_EUNSUPPORTED);
28 }
29
30 static void
handle_157fXX(struct bregs * regs)31 handle_157fXX(struct bregs *regs)
32 {
33 set_code_unimplemented(regs, RET_EUNSUPPORTED);
34 }
35
36 /****************************************************************
37 * Via hooks
38 ****************************************************************/
39
40 int ViaFBsize VARFSEG, ViaRamSpeed VARFSEG;
41
42 static void
via_155f01(struct bregs * regs)43 via_155f01(struct bregs *regs)
44 {
45 regs->eax = 0x5f;
46 regs->cl = 2; // panel type = 2 = 1024 * 768
47 set_success(regs);
48 dprintf(1, "Warning: VGA panel type is hardcoded\n");
49 }
50
51 static void
via_155f02(struct bregs * regs)52 via_155f02(struct bregs *regs)
53 {
54 regs->eax = 0x5f;
55 regs->bx = 2;
56 regs->cx = 0x401; // PAL + crt only
57 regs->dx = 0; // TV Layout - default
58 set_success(regs);
59 dprintf(1, "Warning: VGA TV/CRT output type is hardcoded\n");
60 }
61
62 static void
via_155f18(struct bregs * regs)63 via_155f18(struct bregs *regs)
64 {
65 int fbsize = GET_GLOBAL(ViaFBsize), ramspeed = GET_GLOBAL(ViaRamSpeed);
66 if (fbsize < 0 || ramspeed < 0) {
67 set_code_invalid(regs, RET_EUNSUPPORTED);
68 return;
69 }
70 regs->eax = 0x5f;
71 regs->ebx = 0x500 | (ramspeed << 4) | fbsize;
72 regs->ecx = 0x060;
73 set_success(regs);
74 }
75
76 static void
via_155f19(struct bregs * regs)77 via_155f19(struct bregs *regs)
78 {
79 set_invalid_silent(regs);
80 }
81
82 static void
via_155f(struct bregs * regs)83 via_155f(struct bregs *regs)
84 {
85 switch (regs->al) {
86 case 0x01: via_155f01(regs); break;
87 case 0x02: via_155f02(regs); break;
88 case 0x18: via_155f18(regs); break;
89 case 0x19: via_155f19(regs); break;
90 default: handle_155fXX(regs); break;
91 }
92 }
93
94 static int
getFBSize(struct pci_device * pci)95 getFBSize(struct pci_device *pci)
96 {
97 /* FB config */
98 u8 reg = pci_config_readb(pci->bdf, 0xa1);
99
100 /* GFX disabled ? */
101 if (!(reg & 0x80))
102 return -1;
103
104 static u8 mem_power[] = {0, 3, 4, 5, 6, 7, 8, 9};
105 return mem_power[(reg >> 4) & 0x7];
106 }
107
108 static int
getViaRamSpeed(struct pci_device * pci)109 getViaRamSpeed(struct pci_device *pci)
110 {
111 return (pci_config_readb(pci->bdf, 0x90) & 0x07) + 3;
112 }
113
114 static int
getAMDRamSpeed(void)115 getAMDRamSpeed(void)
116 {
117 struct pci_device *pci = pci_find_device(PCI_VENDOR_ID_AMD
118 , PCI_DEVICE_ID_AMD_K8_NB_MEMCTL);
119 if (!pci)
120 return -1;
121
122 /* mem clk 0 = DDR2 400 */
123 return (pci_config_readb(pci->bdf, 0x94) & 0x7) + 6;
124 }
125
126 /* int 0x15 - 5f18
127
128 ECX = unknown/don't care
129 EBX[3..0] Frame Buffer Size 2^N MiB
130 EBX[7..4] Memory speed:
131 0: SDR 66Mhz
132 1: SDR 100Mhz
133 2: SDR 133Mhz
134 3: DDR 100Mhz (PC1600 or DDR200)
135 4: DDR 133Mhz (PC2100 or DDR266)
136 5: DDR 166Mhz (PC2700 or DDR333)
137 6: DDR 200Mhz (PC3200 or DDR400)
138 7: DDR2 133Mhz (DDR2 533)
139 8: DDR2 166Mhz (DDR2 667)
140 9: DDR2 200Mhz (DDR2 800)
141 A: DDR2 233Mhz (DDR2 1066)
142 B: and above: Unknown
143 EBX[?..8] Total memory size?
144 EAX = 0x5f for success
145 */
146
147 #define PCI_DEVICE_ID_VIA_K8M890CE_3 0x3336
148 #define PCI_DEVICE_ID_VIA_VX855_MEMCTRL 0x3409
149
150 static void
via_setup(struct pci_device * pci)151 via_setup(struct pci_device *pci)
152 {
153 VGAHookHandlerType = VH_VIA;
154
155 struct pci_device *d = pci_find_device(PCI_VENDOR_ID_VIA
156 , PCI_DEVICE_ID_VIA_K8M890CE_3);
157 if (d) {
158 ViaFBsize = getFBSize(d);
159 ViaRamSpeed = getAMDRamSpeed();
160 return;
161 }
162 d = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855_MEMCTRL);
163 if (d) {
164 ViaFBsize = getFBSize(d);
165 ViaRamSpeed = getViaRamSpeed(d);
166 return;
167 }
168
169 dprintf(1, "Warning: VGA memory size and speed is hardcoded\n");
170 ViaFBsize = 5; // 32M frame buffer
171 ViaRamSpeed = 4; // MCLK = DDR266
172 }
173
174
175 /****************************************************************
176 * Intel VGA hooks
177 ****************************************************************/
178
179 u8 IntelDisplayType VARFSEG, IntelDisplayId VARFSEG;
180
181 static void
intel_155f35(struct bregs * regs)182 intel_155f35(struct bregs *regs)
183 {
184 regs->ax = 0x005f;
185 regs->cl = GET_GLOBAL(IntelDisplayType);
186 set_success(regs);
187 }
188
189 static void
intel_155f40(struct bregs * regs)190 intel_155f40(struct bregs *regs)
191 {
192 regs->ax = 0x005f;
193 regs->cl = GET_GLOBAL(IntelDisplayId);
194 set_success(regs);
195 }
196
197 static void
intel_155f50(struct bregs * regs)198 intel_155f50(struct bregs *regs)
199 {
200 /* Mandatory hook on some Dell laptops */
201 regs->ax = 0x005f;
202 set_success(regs);
203 }
204
205 static void
intel_155f(struct bregs * regs)206 intel_155f(struct bregs *regs)
207 {
208 switch (regs->al) {
209 case 0x35: intel_155f35(regs); break;
210 case 0x40: intel_155f40(regs); break;
211 case 0x50: intel_155f50(regs); break;
212 default: handle_155fXX(regs); break;
213 }
214 }
215
216 #define BOOT_DISPLAY_DEFAULT (0)
217 #define BOOT_DISPLAY_CRT (1 << 0)
218 #define BOOT_DISPLAY_TV (1 << 1)
219 #define BOOT_DISPLAY_EFP (1 << 2)
220 #define BOOT_DISPLAY_LCD (1 << 3)
221 #define BOOT_DISPLAY_CRT2 (1 << 4)
222 #define BOOT_DISPLAY_TV2 (1 << 5)
223 #define BOOT_DISPLAY_EFP2 (1 << 6)
224 #define BOOT_DISPLAY_LCD2 (1 << 7)
225
226 static void
intel_setup(struct pci_device * pci)227 intel_setup(struct pci_device *pci)
228 {
229 VGAHookHandlerType = VH_INTEL;
230
231 IntelDisplayType = BOOT_DISPLAY_DEFAULT;
232 IntelDisplayId = 3;
233 }
234
235 static void
roda_setup(struct pci_device * pci)236 roda_setup(struct pci_device *pci)
237 {
238 VGAHookHandlerType = VH_INTEL;
239 // IntelDisplayType = BOOT_DISPLAY_DEFAULT;
240 IntelDisplayType = BOOT_DISPLAY_LCD;
241 // IntelDisplayId = inb(0x60f) & 0x0f; // Correct according to Crete
242 IntelDisplayId = 3; // Correct according to empirical studies
243 }
244
245 static void
kontron_setup(struct pci_device * pci)246 kontron_setup(struct pci_device *pci)
247 {
248 VGAHookHandlerType = VH_INTEL;
249 IntelDisplayType = BOOT_DISPLAY_CRT;
250 IntelDisplayId = 3;
251 }
252
253 static void
getac_setup(struct pci_device * pci)254 getac_setup(struct pci_device *pci)
255 {
256 }
257
258 /****************************************************************
259 * Silicon Motion hooks
260 ****************************************************************/
261
262 u8 SmiBootDisplay VARFSEG; // 1: LCD, 2: CRT, 3: Both */
263
264 static void
smi_157f02(struct bregs * regs)265 smi_157f02(struct bregs *regs)
266 {
267 /* Boot Display Device Override */
268 regs->ax = 0x007f;
269 regs->bl = GET_GLOBAL(SmiBootDisplay);
270 set_success(regs);
271 }
272
273 static void
smi_157f14(struct bregs * regs)274 smi_157f14(struct bregs *regs)
275 {
276 /* ReduceOn support default status */
277 regs->ax = 0x007f;
278 regs->bl = 0x00;
279 set_success(regs);
280 }
281
282 static void
smi_157f(struct bregs * regs)283 smi_157f(struct bregs *regs)
284 {
285 switch (regs->al) {
286 case 0x02: smi_157f02(regs); break;
287 case 0x14: smi_157f14(regs); break;
288 default: handle_157fXX(regs); break;
289 }
290 }
291
292 static void
winent_mb6047_setup(struct pci_device * pci)293 winent_mb6047_setup(struct pci_device *pci)
294 {
295 VGAHookHandlerType = VH_SMI;
296 SmiBootDisplay = 0x02;
297 }
298
299 /****************************************************************
300 * Entry and setup
301 ****************************************************************/
302
303 // Main 16bit entry point
304 void
handle_155f(struct bregs * regs)305 handle_155f(struct bregs *regs)
306 {
307 if (!CONFIG_VGAHOOKS) {
308 handle_155fXX(regs);
309 return;
310 }
311
312 int htype = GET_GLOBAL(VGAHookHandlerType);
313 switch (htype) {
314 case VH_VIA: via_155f(regs); break;
315 case VH_INTEL: intel_155f(regs); break;
316 default: handle_155fXX(regs); break;
317 }
318 }
319
320 // Main 16bit entry point
321 void
handle_157f(struct bregs * regs)322 handle_157f(struct bregs *regs)
323 {
324 if (!CONFIG_VGAHOOKS) {
325 handle_157fXX(regs);
326 return;
327 }
328
329 int htype = GET_GLOBAL(VGAHookHandlerType);
330 switch (htype) {
331 case VH_SMI: smi_157f(regs); break;
332 default: handle_157fXX(regs); break;
333 }
334 }
335
336 // Setup
337 void
vgahook_setup(struct pci_device * pci)338 vgahook_setup(struct pci_device *pci)
339 {
340 if (!CONFIG_VGAHOOKS)
341 return;
342
343 if (strcmp(CBvendor, "KONTRON") == 0 && strcmp(CBpart, "986LCD-M") == 0)
344 kontron_setup(pci);
345 else if (strcmp(CBvendor, "GETAC") == 0 && strcmp(CBpart, "P470") == 0)
346 getac_setup(pci);
347 else if (strcmp(CBvendor, "RODA") == 0 && strcmp(CBpart, "RK886EX") == 0)
348 roda_setup(pci);
349 else if (strcmp(CBvendor, "Win Enterprise") == 0 && strcmp(CBpart, "MB6047") == 0)
350 winent_mb6047_setup(pci);
351 else if (pci->vendor == PCI_VENDOR_ID_VIA)
352 via_setup(pci);
353 else if (pci->vendor == PCI_VENDOR_ID_INTEL)
354 intel_setup(pci);
355 }
356