blob: 20a2e2e2947bd7f48ac822b5adac0322f23d2a3c [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'Connordfefeb52009-12-13 13:04:17 -05007#include "bregs.h" // set_code_invalid
Kevin O'Connor47358772008-12-26 13:01:23 -05008#include "biosvar.h" // GET_GLOBAL
9#include "pci.h" // pci_find_device
Kevin O'Connor22e1b912009-07-19 18:52:46 -040010#include "pci_regs.h" // PCI_VENDOR_ID
Kevin O'Connor47358772008-12-26 13:01:23 -050011#include "pci_ids.h" // PCI_VENDOR_ID_VIA
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040012#include "util.h" // handle_155f
13#include "config.h" // CONFIG_*
14
Kevin O'Connorc1de91b2011-07-02 13:50:21 -040015#define VH_VIA 1
16#define VH_INTEL 2
Kevin O'Connor22e1b912009-07-19 18:52:46 -040017
Kevin O'Connorc1de91b2011-07-02 13:50:21 -040018int VGAHookHandlerType VAR16VISIBLE;
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +020019
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040020static void
Kevin O'Connor22e1b912009-07-19 18:52:46 -040021handle_155fXX(struct bregs *regs)
22{
Kevin O'Connordfefeb52009-12-13 13:04:17 -050023 set_code_unimplemented(regs, RET_EUNSUPPORTED);
Kevin O'Connor22e1b912009-07-19 18:52:46 -040024}
25
26
27/****************************************************************
28 * Via hooks
29 ****************************************************************/
30
Kevin O'Connorc1de91b2011-07-02 13:50:21 -040031int ViaFBsize VAR16VISIBLE, ViaRamSpeed VAR16VISIBLE;
32
Kevin O'Connor22e1b912009-07-19 18:52:46 -040033static void
34via_155f01(struct bregs *regs)
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040035{
36 regs->eax = 0x5f;
37 regs->cl = 2; // panel type = 2 = 1024 * 768
38 set_success(regs);
Kevin O'Connor47358772008-12-26 13:01:23 -050039 dprintf(1, "Warning: VGA panel type is hardcoded\n");
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040040}
41
42static void
Kevin O'Connor22e1b912009-07-19 18:52:46 -040043via_155f02(struct bregs *regs)
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040044{
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);
Kevin O'Connor47358772008-12-26 13:01:23 -050050 dprintf(1, "Warning: VGA TV/CRT output type is hardcoded\n");
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040051}
52
Kevin O'Connorc1de91b2011-07-02 13:50:21 -040053static void
54via_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
67static void
68via_155f19(struct bregs *regs)
69{
70 set_invalid_silent(regs);
71}
72
73static void
74via_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
Kevin O'Connor47358772008-12-26 13:01:23 -050085static int
Kevin O'Connor0cd70052011-07-02 14:04:19 -040086getFBSize(struct pci_device *pci)
Kevin O'Connor47358772008-12-26 13:01:23 -050087{
Kevin O'Connor47358772008-12-26 13:01:23 -050088 /* FB config */
Kevin O'Connor0cd70052011-07-02 14:04:19 -040089 u8 reg = pci_config_readb(pci->bdf, 0xa1);
Kevin O'Connor47358772008-12-26 13:01:23 -050090
91 /* GFX disabled ? */
92 if (!(reg & 0x80))
Kevin O'Connor22e1b912009-07-19 18:52:46 -040093 return -1;
Kevin O'Connor47358772008-12-26 13:01:23 -050094
Kevin O'Connorc1de91b2011-07-02 13:50:21 -040095 static u8 mem_power[] = {0, 3, 4, 5, 6, 7, 8, 9};
96 return mem_power[(reg >> 4) & 0x7];
Kevin O'Connor47358772008-12-26 13:01:23 -050097}
98
99static int
Kevin O'Connor0cd70052011-07-02 14:04:19 -0400100getViaRamSpeed(struct pci_device *pci)
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400101{
Kevin O'Connor0cd70052011-07-02 14:04:19 -0400102 return (pci_config_readb(pci->bdf, 0x90) & 0x07) + 3;
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400103}
104
105static int
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500106getAMDRamSpeed(void)
Kevin O'Connor47358772008-12-26 13:01:23 -0500107{
Kevin O'Connor0cd70052011-07-02 14:04:19 -0400108 struct pci_device *pci = pci_find_device(PCI_VENDOR_ID_AMD
109 , PCI_DEVICE_ID_AMD_K8_NB_MEMCTL);
110 if (!pci)
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400111 return -1;
Kevin O'Connor47358772008-12-26 13:01:23 -0500112
113 /* mem clk 0 = DDR2 400 */
Kevin O'Connor0cd70052011-07-02 14:04:19 -0400114 return (pci_config_readb(pci->bdf, 0x94) & 0x7) + 6;
Kevin O'Connor47358772008-12-26 13:01:23 -0500115}
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
Kevin O'Connor47358772008-12-26 13:01:23 -0500136*/
137
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400138#define PCI_DEVICE_ID_VIA_K8M890CE_3 0x3336
139#define PCI_DEVICE_ID_VIA_VX855_MEMCTRL 0x3409
140
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400141static void
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400142via_setup(struct pci_device *pci)
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400143{
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400144 VGAHookHandlerType = VH_VIA;
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400145
Kevin O'Connor0cd70052011-07-02 14:04:19 -0400146 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);
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400150 ViaRamSpeed = getAMDRamSpeed();
151 return;
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400152 }
Kevin O'Connor0cd70052011-07-02 14:04:19 -0400153 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);
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400157 return;
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400158 }
159
160 dprintf(1, "Warning: VGA memory size and speed is hardcoded\n");
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400161 ViaFBsize = 5; // 32M frame buffer
162 ViaRamSpeed = 4; // MCLK = DDR266
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400163}
164
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400165
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200166/****************************************************************
167 * Intel VGA hooks
168 ****************************************************************/
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400169
170u8 IntelDisplayType VAR16VISIBLE, IntelDisplayId VAR16VISIBLE;
171
172static void
173intel_155f35(struct bregs *regs)
174{
175 regs->ax = 0x005f;
176 regs->cl = GET_GLOBAL(IntelDisplayType);
177 set_success(regs);
178}
179
180static void
181intel_155f40(struct bregs *regs)
182{
183 regs->ax = 0x005f;
184 regs->cl = GET_GLOBAL(IntelDisplayId);
185 set_success(regs);
186}
187
188static void
Julian Pidancet02145152012-02-05 04:51:06 +0000189intel_155f50(struct bregs *regs)
190{
191 /* Mandatory hook on some Dell laptops */
192 regs->ax = 0x005f;
193 set_success(regs);
194}
195
196static void
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400197intel_155f(struct bregs *regs)
198{
199 switch (regs->al) {
200 case 0x35: intel_155f35(regs); break;
201 case 0x40: intel_155f40(regs); break;
Julian Pidancet02145152012-02-05 04:51:06 +0000202 case 0x50: intel_155f50(regs); break;
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400203 default: handle_155fXX(regs); break;
204 }
205}
206
207#define BOOT_DISPLAY_DEFAULT (0)
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200208#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)
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400216
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200217static void
Julian Pidancet02145152012-02-05 04:51:06 +0000218intel_setup(struct pci_device *pci)
219{
220 VGAHookHandlerType = VH_INTEL;
221
222 IntelDisplayType = BOOT_DISPLAY_DEFAULT;
223 IntelDisplayId = 3;
224}
225
226static void
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400227roda_setup(struct pci_device *pci)
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200228{
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400229 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
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200234}
235
236static void
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400237kontron_setup(struct pci_device *pci)
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200238{
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400239 VGAHookHandlerType = VH_INTEL;
240 IntelDisplayType = BOOT_DISPLAY_CRT;
241 IntelDisplayId = 3;
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200242}
243
244static void
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400245getac_setup(struct pci_device *pci)
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200246{
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200247}
248
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400249
250/****************************************************************
251 * Entry and setup
252 ****************************************************************/
253
254// Main 16bit entry point
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400255void
256handle_155f(struct bregs *regs)
257{
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400258 if (!CONFIG_VGAHOOKS) {
259 handle_155fXX(regs);
260 return;
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400261 }
262
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400263 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 }
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400269}
270
271// Setup
272void
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400273vgahook_setup(struct pci_device *pci)
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400274{
Julian Pidancet02145152012-02-05 04:51:06 +0000275 if (!CONFIG_VGAHOOKS)
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400276 return;
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200277
Kevin O'Connorc1de91b2011-07-02 13:50:21 -0400278 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);
Julian Pidancet02145152012-02-05 04:51:06 +0000286 else if (pci->vendor == PCI_VENDOR_ID_INTEL)
287 intel_setup(pci);
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400288}