blob: 6a4acfeaf0e196f37b28923aef48f27f167a6bcf [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'Connor2d2fa312013-09-14 21:55:26 -040010#include "hw/pci.h" // pci_find_device
11#include "hw/pci_ids.h" // PCI_VENDOR_ID_VIA
12#include "hw/pci_regs.h" // PCI_VENDOR_ID
13#include "output.h" // dprintf
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -040014#include "string.h" // strcmp
Jonathan A. Kollasche9a3e122013-10-20 12:48:56 -050015#include "util.h" // handle_155f, handle_157f
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040016
Kevin O'Connorc1de91b2011-07-02 13:50:21 -040017#define VH_VIA 1
18#define VH_INTEL 2
Jonathan A. Kollasche9a3e122013-10-20 12:48:56 -050019#define VH_SMI 3
Kevin O'Connor22e1b912009-07-19 18:52:46 -040020
Kevin O'Connor89a2f962013-02-18 23:36:03 -050021int VGAHookHandlerType VARFSEG;
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +020022
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040023static void
Kevin O'Connor22e1b912009-07-19 18:52:46 -040024handle_155fXX(struct bregs *regs)
25{
Kevin O'Connordfefeb52009-12-13 13:04:17 -050026 set_code_unimplemented(regs, RET_EUNSUPPORTED);
Kevin O'Connor22e1b912009-07-19 18:52:46 -040027}
28
Jonathan A. Kollasche9a3e122013-10-20 12:48:56 -050029static void
30handle_157fXX(struct bregs *regs)
31{
32 set_code_unimplemented(regs, RET_EUNSUPPORTED);
33}
Kevin O'Connor22e1b912009-07-19 18:52:46 -040034
35/****************************************************************
36 * Via hooks
37 ****************************************************************/
38
Kevin O'Connor89a2f962013-02-18 23:36:03 -050039int ViaFBsize VARFSEG, ViaRamSpeed VARFSEG;
Kevin O'Connorc1de91b2011-07-02 13:50:21 -040040
Kevin O'Connor22e1b912009-07-19 18:52:46 -040041static void
42via_155f01(struct bregs *regs)
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040043{
44 regs->eax = 0x5f;
45 regs->cl = 2; // panel type = 2 = 1024 * 768
46 set_success(regs);
Kevin O'Connor47358772008-12-26 13:01:23 -050047 dprintf(1, "Warning: VGA panel type is hardcoded\n");
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040048}
49
50static void
Kevin O'Connor22e1b912009-07-19 18:52:46 -040051via_155f02(struct bregs *regs)
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040052{
53 regs->eax = 0x5f;
54 regs->bx = 2;
55 regs->cx = 0x401; // PAL + crt only
56 regs->dx = 0; // TV Layout - default
57 set_success(regs);
Kevin O'Connor47358772008-12-26 13:01:23 -050058 dprintf(1, "Warning: VGA TV/CRT output type is hardcoded\n");
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040059}
60
Kevin O'Connorc1de91b2011-07-02 13:50:21 -040061static void
62via_155f18(struct bregs *regs)
63{
64 int fbsize = GET_GLOBAL(ViaFBsize), ramspeed = GET_GLOBAL(ViaRamSpeed);
65 if (fbsize < 0 || ramspeed < 0) {
66 set_code_invalid(regs, RET_EUNSUPPORTED);
67 return;
68 }
69 regs->eax = 0x5f;
70 regs->ebx = 0x500 | (ramspeed << 4) | fbsize;
71 regs->ecx = 0x060;
72 set_success(regs);
73}
74
75static void
76via_155f19(struct bregs *regs)
77{
78 set_invalid_silent(regs);
79}
80
81static void
82via_155f(struct bregs *regs)
83{
84 switch (regs->al) {
85 case 0x01: via_155f01(regs); break;
86 case 0x02: via_155f02(regs); break;
87 case 0x18: via_155f18(regs); break;
88 case 0x19: via_155f19(regs); break;
89 default: handle_155fXX(regs); break;
90 }
91}
92
Kevin O'Connor47358772008-12-26 13:01:23 -050093static int
Kevin O'Connor0cd70052011-07-02 14:04:19 -040094getFBSize(struct pci_device *pci)
Kevin O'Connor47358772008-12-26 13:01:23 -050095{
Kevin O'Connor47358772008-12-26 13:01:23 -050096 /* FB config */
Kevin O'Connor0cd70052011-07-02 14:04:19 -040097 u8 reg = pci_config_readb(pci->bdf, 0xa1);
Kevin O'Connor47358772008-12-26 13:01:23 -050098
99 /* GFX disabled ? */
100 if (!(reg & 0x80))
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400101 return -1;
Kevin O'Connor47358772008-12-26 13:01:23 -0500102
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400103 static u8 mem_power[] = {0, 3, 4, 5, 6, 7, 8, 9};
104 return mem_power[(reg >> 4) & 0x7];
Kevin O'Connor47358772008-12-26 13:01:23 -0500105}
106
107static int
Kevin O'Connor0cd70052011-07-02 14:04:19 -0400108getViaRamSpeed(struct pci_device *pci)
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400109{
Kevin O'Connor0cd70052011-07-02 14:04:19 -0400110 return (pci_config_readb(pci->bdf, 0x90) & 0x07) + 3;
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400111}
112
113static int
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500114getAMDRamSpeed(void)
Kevin O'Connor47358772008-12-26 13:01:23 -0500115{
Kevin O'Connor0cd70052011-07-02 14:04:19 -0400116 struct pci_device *pci = pci_find_device(PCI_VENDOR_ID_AMD
117 , PCI_DEVICE_ID_AMD_K8_NB_MEMCTL);
118 if (!pci)
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400119 return -1;
Kevin O'Connor47358772008-12-26 13:01:23 -0500120
121 /* mem clk 0 = DDR2 400 */
Kevin O'Connor0cd70052011-07-02 14:04:19 -0400122 return (pci_config_readb(pci->bdf, 0x94) & 0x7) + 6;
Kevin O'Connor47358772008-12-26 13:01:23 -0500123}
124
125/* int 0x15 - 5f18
126
127 ECX = unknown/dont care
128 EBX[3..0] Frame Buffer Size 2^N MiB
129 EBX[7..4] Memory speed:
130 0: SDR 66Mhz
131 1: SDR 100Mhz
132 2: SDR 133Mhz
133 3: DDR 100Mhz (PC1600 or DDR200)
134 4: DDR 133Mhz (PC2100 or DDR266)
135 5: DDR 166Mhz (PC2700 or DDR333)
136 6: DDR 200Mhz (PC3200 or DDR400)
137 7: DDR2 133Mhz (DDR2 533)
138 8: DDR2 166Mhz (DDR2 667)
139 9: DDR2 200Mhz (DDR2 800)
140 A: DDR2 233Mhz (DDR2 1066)
141 B: and above: Unknown
142 EBX[?..8] Total memory size?
143 EAX = 0x5f for success
Kevin O'Connor47358772008-12-26 13:01:23 -0500144*/
145
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400146#define PCI_DEVICE_ID_VIA_K8M890CE_3 0x3336
147#define PCI_DEVICE_ID_VIA_VX855_MEMCTRL 0x3409
148
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400149static void
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400150via_setup(struct pci_device *pci)
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400151{
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400152 VGAHookHandlerType = VH_VIA;
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400153
Kevin O'Connor0cd70052011-07-02 14:04:19 -0400154 struct pci_device *d = pci_find_device(PCI_VENDOR_ID_VIA
155 , PCI_DEVICE_ID_VIA_K8M890CE_3);
156 if (d) {
157 ViaFBsize = getFBSize(d);
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400158 ViaRamSpeed = getAMDRamSpeed();
159 return;
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400160 }
Kevin O'Connor0cd70052011-07-02 14:04:19 -0400161 d = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855_MEMCTRL);
162 if (d) {
163 ViaFBsize = getFBSize(d);
164 ViaRamSpeed = getViaRamSpeed(d);
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400165 return;
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400166 }
167
168 dprintf(1, "Warning: VGA memory size and speed is hardcoded\n");
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400169 ViaFBsize = 5; // 32M frame buffer
170 ViaRamSpeed = 4; // MCLK = DDR266
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400171}
172
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400173
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200174/****************************************************************
175 * Intel VGA hooks
176 ****************************************************************/
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400177
Kevin O'Connor89a2f962013-02-18 23:36:03 -0500178u8 IntelDisplayType VARFSEG, IntelDisplayId VARFSEG;
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400179
180static void
181intel_155f35(struct bregs *regs)
182{
183 regs->ax = 0x005f;
184 regs->cl = GET_GLOBAL(IntelDisplayType);
185 set_success(regs);
186}
187
188static void
189intel_155f40(struct bregs *regs)
190{
191 regs->ax = 0x005f;
192 regs->cl = GET_GLOBAL(IntelDisplayId);
193 set_success(regs);
194}
195
196static void
Julian Pidancet02145152012-02-05 04:51:06 +0000197intel_155f50(struct bregs *regs)
198{
199 /* Mandatory hook on some Dell laptops */
200 regs->ax = 0x005f;
201 set_success(regs);
202}
203
204static void
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400205intel_155f(struct bregs *regs)
206{
207 switch (regs->al) {
208 case 0x35: intel_155f35(regs); break;
209 case 0x40: intel_155f40(regs); break;
Julian Pidancet02145152012-02-05 04:51:06 +0000210 case 0x50: intel_155f50(regs); break;
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400211 default: handle_155fXX(regs); break;
212 }
213}
214
215#define BOOT_DISPLAY_DEFAULT (0)
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200216#define BOOT_DISPLAY_CRT (1 << 0)
217#define BOOT_DISPLAY_TV (1 << 1)
218#define BOOT_DISPLAY_EFP (1 << 2)
219#define BOOT_DISPLAY_LCD (1 << 3)
220#define BOOT_DISPLAY_CRT2 (1 << 4)
221#define BOOT_DISPLAY_TV2 (1 << 5)
222#define BOOT_DISPLAY_EFP2 (1 << 6)
223#define BOOT_DISPLAY_LCD2 (1 << 7)
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400224
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200225static void
Julian Pidancet02145152012-02-05 04:51:06 +0000226intel_setup(struct pci_device *pci)
227{
228 VGAHookHandlerType = VH_INTEL;
229
230 IntelDisplayType = BOOT_DISPLAY_DEFAULT;
231 IntelDisplayId = 3;
232}
233
234static void
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400235roda_setup(struct pci_device *pci)
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200236{
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400237 VGAHookHandlerType = VH_INTEL;
238 // IntelDisplayType = BOOT_DISPLAY_DEFAULT;
239 IntelDisplayType = BOOT_DISPLAY_LCD;
240 // IntelDisplayId = inb(0x60f) & 0x0f; // Correct according to Crete
241 IntelDisplayId = 3; // Correct according to empirical studies
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200242}
243
244static void
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400245kontron_setup(struct pci_device *pci)
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200246{
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400247 VGAHookHandlerType = VH_INTEL;
248 IntelDisplayType = BOOT_DISPLAY_CRT;
249 IntelDisplayId = 3;
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200250}
251
252static void
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400253getac_setup(struct pci_device *pci)
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200254{
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200255}
256
Jonathan A. Kollasche9a3e122013-10-20 12:48:56 -0500257/****************************************************************
258 * Silicon Motion hooks
259 ****************************************************************/
260
261u8 SmiBootDisplay VARFSEG; // 1: LCD, 2: CRT, 3: Both */
262
263static void
264smi_157f02(struct bregs *regs)
265{
266 /* Boot Display Device Override */
267 regs->ax = 0x007f;
268 regs->bl = GET_GLOBAL(SmiBootDisplay);
269 set_success(regs);
270}
271
272static void
273smi_157f14(struct bregs *regs)
274{
275 /* ReduceOn support default status */
276 regs->ax = 0x007f;
277 regs->bl = 0x00;
278 set_success(regs);
279}
280
281static void
282smi_157f(struct bregs *regs)
283{
284 switch (regs->al) {
285 case 0x02: smi_157f02(regs); break;
286 case 0x14: smi_157f14(regs); break;
287 default: handle_157fXX(regs); break;
288 }
289}
290
291static void
292winent_mb6047_setup(struct pci_device *pci)
293{
294 VGAHookHandlerType = VH_SMI;
295 SmiBootDisplay = 0x02;
296}
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400297
298/****************************************************************
299 * Entry and setup
300 ****************************************************************/
301
302// Main 16bit entry point
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400303void
304handle_155f(struct bregs *regs)
305{
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400306 if (!CONFIG_VGAHOOKS) {
307 handle_155fXX(regs);
308 return;
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400309 }
310
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400311 int htype = GET_GLOBAL(VGAHookHandlerType);
312 switch (htype) {
313 case VH_VIA: via_155f(regs); break;
314 case VH_INTEL: intel_155f(regs); break;
315 default: handle_155fXX(regs); break;
316 }
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400317}
318
Jonathan A. Kollasche9a3e122013-10-20 12:48:56 -0500319// Main 16bit entry point
320void
321handle_157f(struct bregs *regs)
322{
323 if (!CONFIG_VGAHOOKS) {
324 handle_157fXX(regs);
325 return;
326 }
327
328 int htype = GET_GLOBAL(VGAHookHandlerType);
329 switch (htype) {
330 case VH_SMI: smi_157f(regs); break;
331 default: handle_157fXX(regs); break;
332 }
333}
334
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400335// Setup
336void
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400337vgahook_setup(struct pci_device *pci)
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400338{
Julian Pidancet02145152012-02-05 04:51:06 +0000339 if (!CONFIG_VGAHOOKS)
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400340 return;
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200341
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400342 if (strcmp(CBvendor, "KONTRON") == 0 && strcmp(CBpart, "986LCD-M") == 0)
343 kontron_setup(pci);
344 else if (strcmp(CBvendor, "GETAC") == 0 && strcmp(CBpart, "P470") == 0)
345 getac_setup(pci);
346 else if (strcmp(CBvendor, "RODA") == 0 && strcmp(CBpart, "RK886EX") == 0)
347 roda_setup(pci);
Jonathan A. Kollasche9a3e122013-10-20 12:48:56 -0500348 else if (strcmp(CBvendor, "Win Enterprise") == 0 && strcmp(CBpart, "MB6047") == 0)
349 winent_mb6047_setup(pci);
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400350 else if (pci->vendor == PCI_VENDOR_ID_VIA)
351 via_setup(pci);
Julian Pidancet02145152012-02-05 04:51:06 +0000352 else if (pci->vendor == PCI_VENDOR_ID_INTEL)
353 intel_setup(pci);
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400354}