blob: 1f1495329ce5781e3df0ed1385b26c4e04fff5d4 [file] [log] [blame]
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -04001// Hooks for via vgabios calls into main bios.
2//
3// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
4//
Kevin O'Connorb1b7c2a2009-01-15 20:52:58 -05005// This file may be distributed under the terms of the GNU LGPLv3 license.
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -04006
Kevin O'Connor47358772008-12-26 13:01:23 -05007#include "biosvar.h" // GET_GLOBAL
Kevin O'Connor2d2fa312013-09-14 21:55:26 -04008#include "bregs.h" // set_code_invalid
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -04009#include "config.h" // CONFIG_*
Kevin O'Connor4d8510c2016-02-03 01:28:20 -050010#include "hw/pci.h" // pci_config_readb
11#include "hw/pcidevice.h" // pci_find_device
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040012#include "hw/pci_ids.h" // PCI_VENDOR_ID_VIA
13#include "hw/pci_regs.h" // PCI_VENDOR_ID
14#include "output.h" // dprintf
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -040015#include "string.h" // strcmp
Jonathan A. Kollasche9a3e122013-10-20 12:48:56 -050016#include "util.h" // handle_155f, handle_157f
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040017
Kevin O'Connorc1de91b2011-07-02 13:50:21 -040018#define VH_VIA 1
19#define VH_INTEL 2
Jonathan A. Kollasche9a3e122013-10-20 12:48:56 -050020#define VH_SMI 3
Kevin O'Connor22e1b912009-07-19 18:52:46 -040021
Kevin O'Connor89a2f962013-02-18 23:36:03 -050022int VGAHookHandlerType VARFSEG;
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +020023
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040024static void
Kevin O'Connor22e1b912009-07-19 18:52:46 -040025handle_155fXX(struct bregs *regs)
26{
Kevin O'Connordfefeb52009-12-13 13:04:17 -050027 set_code_unimplemented(regs, RET_EUNSUPPORTED);
Kevin O'Connor22e1b912009-07-19 18:52:46 -040028}
29
Jonathan A. Kollasche9a3e122013-10-20 12:48:56 -050030static void
31handle_157fXX(struct bregs *regs)
32{
33 set_code_unimplemented(regs, RET_EUNSUPPORTED);
34}
Kevin O'Connor22e1b912009-07-19 18:52:46 -040035
36/****************************************************************
37 * Via hooks
38 ****************************************************************/
39
Kevin O'Connor89a2f962013-02-18 23:36:03 -050040int ViaFBsize VARFSEG, ViaRamSpeed VARFSEG;
Kevin O'Connorc1de91b2011-07-02 13:50:21 -040041
Kevin O'Connor22e1b912009-07-19 18:52:46 -040042static void
43via_155f01(struct bregs *regs)
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040044{
45 regs->eax = 0x5f;
46 regs->cl = 2; // panel type = 2 = 1024 * 768
47 set_success(regs);
Kevin O'Connor47358772008-12-26 13:01:23 -050048 dprintf(1, "Warning: VGA panel type is hardcoded\n");
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040049}
50
51static void
Kevin O'Connor22e1b912009-07-19 18:52:46 -040052via_155f02(struct bregs *regs)
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040053{
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);
Kevin O'Connor47358772008-12-26 13:01:23 -050059 dprintf(1, "Warning: VGA TV/CRT output type is hardcoded\n");
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040060}
61
Kevin O'Connorc1de91b2011-07-02 13:50:21 -040062static void
63via_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
76static void
77via_155f19(struct bregs *regs)
78{
79 set_invalid_silent(regs);
80}
81
82static void
83via_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
Kevin O'Connor47358772008-12-26 13:01:23 -050094static int
Kevin O'Connor0cd70052011-07-02 14:04:19 -040095getFBSize(struct pci_device *pci)
Kevin O'Connor47358772008-12-26 13:01:23 -050096{
Kevin O'Connor47358772008-12-26 13:01:23 -050097 /* FB config */
Kevin O'Connor0cd70052011-07-02 14:04:19 -040098 u8 reg = pci_config_readb(pci->bdf, 0xa1);
Kevin O'Connor47358772008-12-26 13:01:23 -050099
100 /* GFX disabled ? */
101 if (!(reg & 0x80))
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400102 return -1;
Kevin O'Connor47358772008-12-26 13:01:23 -0500103
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400104 static u8 mem_power[] = {0, 3, 4, 5, 6, 7, 8, 9};
105 return mem_power[(reg >> 4) & 0x7];
Kevin O'Connor47358772008-12-26 13:01:23 -0500106}
107
108static int
Kevin O'Connor0cd70052011-07-02 14:04:19 -0400109getViaRamSpeed(struct pci_device *pci)
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400110{
Kevin O'Connor0cd70052011-07-02 14:04:19 -0400111 return (pci_config_readb(pci->bdf, 0x90) & 0x07) + 3;
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400112}
113
114static int
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500115getAMDRamSpeed(void)
Kevin O'Connor47358772008-12-26 13:01:23 -0500116{
Kevin O'Connor0cd70052011-07-02 14:04:19 -0400117 struct pci_device *pci = pci_find_device(PCI_VENDOR_ID_AMD
118 , PCI_DEVICE_ID_AMD_K8_NB_MEMCTL);
119 if (!pci)
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400120 return -1;
Kevin O'Connor47358772008-12-26 13:01:23 -0500121
122 /* mem clk 0 = DDR2 400 */
Kevin O'Connor0cd70052011-07-02 14:04:19 -0400123 return (pci_config_readb(pci->bdf, 0x94) & 0x7) + 6;
Kevin O'Connor47358772008-12-26 13:01:23 -0500124}
125
126/* int 0x15 - 5f18
127
Stefan Weil6bcacf72015-10-02 08:46:40 +0200128 ECX = unknown/don't care
Kevin O'Connor47358772008-12-26 13:01:23 -0500129 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
Kevin O'Connor47358772008-12-26 13:01:23 -0500145*/
146
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400147#define PCI_DEVICE_ID_VIA_K8M890CE_3 0x3336
148#define PCI_DEVICE_ID_VIA_VX855_MEMCTRL 0x3409
149
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400150static void
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400151via_setup(struct pci_device *pci)
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400152{
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400153 VGAHookHandlerType = VH_VIA;
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400154
Kevin O'Connor0cd70052011-07-02 14:04:19 -0400155 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);
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400159 ViaRamSpeed = getAMDRamSpeed();
160 return;
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400161 }
Kevin O'Connor0cd70052011-07-02 14:04:19 -0400162 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);
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400166 return;
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400167 }
168
169 dprintf(1, "Warning: VGA memory size and speed is hardcoded\n");
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400170 ViaFBsize = 5; // 32M frame buffer
171 ViaRamSpeed = 4; // MCLK = DDR266
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400172}
173
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400174
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200175/****************************************************************
176 * Intel VGA hooks
177 ****************************************************************/
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400178
Kevin O'Connor89a2f962013-02-18 23:36:03 -0500179u8 IntelDisplayType VARFSEG, IntelDisplayId VARFSEG;
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400180
181static void
182intel_155f35(struct bregs *regs)
183{
184 regs->ax = 0x005f;
185 regs->cl = GET_GLOBAL(IntelDisplayType);
186 set_success(regs);
187}
188
189static void
190intel_155f40(struct bregs *regs)
191{
192 regs->ax = 0x005f;
193 regs->cl = GET_GLOBAL(IntelDisplayId);
194 set_success(regs);
195}
196
197static void
Julian Pidancet02145152012-02-05 04:51:06 +0000198intel_155f50(struct bregs *regs)
199{
200 /* Mandatory hook on some Dell laptops */
201 regs->ax = 0x005f;
202 set_success(regs);
203}
204
205static void
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400206intel_155f(struct bregs *regs)
207{
208 switch (regs->al) {
209 case 0x35: intel_155f35(regs); break;
210 case 0x40: intel_155f40(regs); break;
Julian Pidancet02145152012-02-05 04:51:06 +0000211 case 0x50: intel_155f50(regs); break;
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400212 default: handle_155fXX(regs); break;
213 }
214}
215
216#define BOOT_DISPLAY_DEFAULT (0)
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200217#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)
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400225
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200226static void
Julian Pidancet02145152012-02-05 04:51:06 +0000227intel_setup(struct pci_device *pci)
228{
229 VGAHookHandlerType = VH_INTEL;
230
231 IntelDisplayType = BOOT_DISPLAY_DEFAULT;
232 IntelDisplayId = 3;
233}
234
235static void
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400236roda_setup(struct pci_device *pci)
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200237{
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400238 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
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200243}
244
245static void
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400246kontron_setup(struct pci_device *pci)
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200247{
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400248 VGAHookHandlerType = VH_INTEL;
249 IntelDisplayType = BOOT_DISPLAY_CRT;
250 IntelDisplayId = 3;
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200251}
252
253static void
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400254getac_setup(struct pci_device *pci)
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200255{
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200256}
257
Jonathan A. Kollasche9a3e122013-10-20 12:48:56 -0500258/****************************************************************
259 * Silicon Motion hooks
260 ****************************************************************/
261
262u8 SmiBootDisplay VARFSEG; // 1: LCD, 2: CRT, 3: Both */
263
264static void
265smi_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
273static void
274smi_157f14(struct bregs *regs)
275{
276 /* ReduceOn support default status */
277 regs->ax = 0x007f;
278 regs->bl = 0x00;
279 set_success(regs);
280}
281
282static void
283smi_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
292static void
293winent_mb6047_setup(struct pci_device *pci)
294{
295 VGAHookHandlerType = VH_SMI;
296 SmiBootDisplay = 0x02;
297}
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400298
299/****************************************************************
300 * Entry and setup
301 ****************************************************************/
302
303// Main 16bit entry point
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400304void
305handle_155f(struct bregs *regs)
306{
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400307 if (!CONFIG_VGAHOOKS) {
308 handle_155fXX(regs);
309 return;
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400310 }
311
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400312 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 }
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400318}
319
Jonathan A. Kollasche9a3e122013-10-20 12:48:56 -0500320// Main 16bit entry point
321void
322handle_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
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400336// Setup
337void
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400338vgahook_setup(struct pci_device *pci)
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400339{
Julian Pidancet02145152012-02-05 04:51:06 +0000340 if (!CONFIG_VGAHOOKS)
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400341 return;
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200342
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400343 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);
Jonathan A. Kollasche9a3e122013-10-20 12:48:56 -0500349 else if (strcmp(CBvendor, "Win Enterprise") == 0 && strcmp(CBpart, "MB6047") == 0)
350 winent_mb6047_setup(pci);
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400351 else if (pci->vendor == PCI_VENDOR_ID_VIA)
352 via_setup(pci);
Julian Pidancet02145152012-02-05 04:51:06 +0000353 else if (pci->vendor == PCI_VENDOR_ID_INTEL)
354 intel_setup(pci);
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400355}