blob: eb4dfa890ab52c8a49601c592b633ba95b724164 [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'Connor22e1b912009-07-19 18:52:46 -040015// The Bus/Dev/Fn of the primary VGA device.
Kevin O'Connor4d96edc2010-09-25 14:53:15 -040016int VGAbdf VAR16VISIBLE = -1;
Kevin O'Connor22e1b912009-07-19 18:52:46 -040017// Coreboot board detected.
Kevin O'Connor372e0712009-09-09 09:51:31 -040018int CBmainboard VAR16VISIBLE;
Kevin O'Connor22e1b912009-07-19 18:52:46 -040019
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +020020#define MAINBOARD_DEFAULT 0
21#define KONTRON_986LCD_M 1
22#define GETAC_P470 2
23#define RODA_RK886EX 3
24
25struct mainboards {
26 char *vendor;
27 char *device;
28 int type;
29};
30
31struct mainboards mainboard_list[] = {
32 { "KONTRON", "986LCD-M", KONTRON_986LCD_M },
33 { "GETAC", "P470", GETAC_P470 },
34 { "RODA", "RK886EX", RODA_RK886EX },
35};
36
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040037static void
Kevin O'Connor22e1b912009-07-19 18:52:46 -040038handle_155fXX(struct bregs *regs)
39{
Kevin O'Connordfefeb52009-12-13 13:04:17 -050040 set_code_unimplemented(regs, RET_EUNSUPPORTED);
Kevin O'Connor22e1b912009-07-19 18:52:46 -040041}
42
43
44/****************************************************************
45 * Via hooks
46 ****************************************************************/
47
48static void
49via_155f01(struct bregs *regs)
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040050{
51 regs->eax = 0x5f;
52 regs->cl = 2; // panel type = 2 = 1024 * 768
53 set_success(regs);
Kevin O'Connor47358772008-12-26 13:01:23 -050054 dprintf(1, "Warning: VGA panel type is hardcoded\n");
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040055}
56
57static void
Kevin O'Connor22e1b912009-07-19 18:52:46 -040058via_155f02(struct bregs *regs)
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040059{
60 regs->eax = 0x5f;
61 regs->bx = 2;
62 regs->cx = 0x401; // PAL + crt only
63 regs->dx = 0; // TV Layout - default
64 set_success(regs);
Kevin O'Connor47358772008-12-26 13:01:23 -050065 dprintf(1, "Warning: VGA TV/CRT output type is hardcoded\n");
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -040066}
67
Kevin O'Connor47358772008-12-26 13:01:23 -050068static int
Kevin O'Connor22e1b912009-07-19 18:52:46 -040069getFBSize(u16 bdf)
Kevin O'Connor47358772008-12-26 13:01:23 -050070{
Kevin O'Connor47358772008-12-26 13:01:23 -050071 /* FB config */
72 u8 reg = pci_config_readb(bdf, 0xa1);
73
74 /* GFX disabled ? */
75 if (!(reg & 0x80))
Kevin O'Connor22e1b912009-07-19 18:52:46 -040076 return -1;
Kevin O'Connor47358772008-12-26 13:01:23 -050077
Kevin O'Connor92f95b02008-12-29 20:42:40 -050078 static u8 mem_power[] VAR16 = {0, 3, 4, 5, 6, 7, 8, 9};
Kevin O'Connor47358772008-12-26 13:01:23 -050079 return GET_GLOBAL(mem_power[(reg >> 4) & 0x7]);
Kevin O'Connor47358772008-12-26 13:01:23 -050080}
81
82static int
Kevin O'Connor22e1b912009-07-19 18:52:46 -040083getViaRamSpeed(u16 bdf)
84{
85 return (pci_config_readb(bdf, 0x90) & 0x07) + 3;
86}
87
88static int
Kevin O'Connor1ca05b02010-01-03 17:43:37 -050089getAMDRamSpeed(void)
Kevin O'Connor47358772008-12-26 13:01:23 -050090{
91 int bdf = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MEMCTL);
92 if (bdf < 0)
Kevin O'Connor22e1b912009-07-19 18:52:46 -040093 return -1;
Kevin O'Connor47358772008-12-26 13:01:23 -050094
95 /* mem clk 0 = DDR2 400 */
Kevin O'Connor22e1b912009-07-19 18:52:46 -040096 return (pci_config_readb(bdf, 0x94) & 0x7) + 6;
Kevin O'Connor47358772008-12-26 13:01:23 -050097}
98
99/* int 0x15 - 5f18
100
101 ECX = unknown/dont care
102 EBX[3..0] Frame Buffer Size 2^N MiB
103 EBX[7..4] Memory speed:
104 0: SDR 66Mhz
105 1: SDR 100Mhz
106 2: SDR 133Mhz
107 3: DDR 100Mhz (PC1600 or DDR200)
108 4: DDR 133Mhz (PC2100 or DDR266)
109 5: DDR 166Mhz (PC2700 or DDR333)
110 6: DDR 200Mhz (PC3200 or DDR400)
111 7: DDR2 133Mhz (DDR2 533)
112 8: DDR2 166Mhz (DDR2 667)
113 9: DDR2 200Mhz (DDR2 800)
114 A: DDR2 233Mhz (DDR2 1066)
115 B: and above: Unknown
116 EBX[?..8] Total memory size?
117 EAX = 0x5f for success
Kevin O'Connor47358772008-12-26 13:01:23 -0500118*/
119
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400120#define PCI_DEVICE_ID_VIA_K8M890CE_3 0x3336
121#define PCI_DEVICE_ID_VIA_VX855_MEMCTRL 0x3409
122
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400123static void
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400124via_155f18(struct bregs *regs)
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400125{
Kevin O'Connorf9b25d32010-01-03 18:09:08 -0500126 int ramspeed, fbsize;
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400127
128 int bdf = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_K8M890CE_3);
129 if (bdf >= 0) {
130 fbsize = getFBSize(bdf);
131 ramspeed = getAMDRamSpeed();
132 goto done;
133 }
134 bdf = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855_MEMCTRL);
135 if (bdf >= 0) {
136 fbsize = getFBSize(bdf);
137 ramspeed = getViaRamSpeed(bdf);
138 goto done;
139 }
140
141 dprintf(1, "Warning: VGA memory size and speed is hardcoded\n");
142 fbsize = 5; // 32M frame buffer
143 ramspeed = 4; // MCLK = DDR266
144
145done:
146 if (fbsize < 0 || ramspeed < 0) {
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500147 set_code_invalid(regs, RET_EUNSUPPORTED);
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400148 return;
149 }
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400150 regs->eax = 0x5f;
Kevin O'Connor47358772008-12-26 13:01:23 -0500151 regs->ebx = 0x500 | (ramspeed << 4) | fbsize;
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400152 regs->ecx = 0x060;
153 set_success(regs);
154}
155
156static void
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400157via_155f19(struct bregs *regs)
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400158{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500159 set_invalid_silent(regs);
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400160}
161
162static void
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400163via_155f(struct bregs *regs)
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400164{
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400165 switch (regs->al) {
166 case 0x01: via_155f01(regs); break;
167 case 0x02: via_155f02(regs); break;
168 case 0x18: via_155f18(regs); break;
169 case 0x19: via_155f19(regs); break;
170 default: handle_155fXX(regs); break;
171 }
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400172}
173
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200174/****************************************************************
175 * Intel VGA hooks
176 ****************************************************************/
177#define BOOT_DISPLAY_DEFAULT (0)
178#define BOOT_DISPLAY_CRT (1 << 0)
179#define BOOT_DISPLAY_TV (1 << 1)
180#define BOOT_DISPLAY_EFP (1 << 2)
181#define BOOT_DISPLAY_LCD (1 << 3)
182#define BOOT_DISPLAY_CRT2 (1 << 4)
183#define BOOT_DISPLAY_TV2 (1 << 5)
184#define BOOT_DISPLAY_EFP2 (1 << 6)
185#define BOOT_DISPLAY_LCD2 (1 << 7)
186
187static void
188roda_155f35(struct bregs *regs)
189{
190 regs->ax = 0x005f;
191 // regs->cl = BOOT_DISPLAY_DEFAULT;
192 regs->cl = BOOT_DISPLAY_LCD;
193 set_success(regs);
194}
195
196static void
197roda_155f40(struct bregs *regs)
198{
199 u8 display_id;
200 //display_id = inb(0x60f) & 0x0f; // Correct according to Crete
201 display_id = 3; // Correct according to empirical studies
202
203 regs->ax = 0x005f;
204 regs->cl = display_id;
205 set_success(regs);
206}
207
208static void
209roda_155f(struct bregs *regs)
210{
211 dprintf(1, "Executing RODA specific interrupt %02x.\n", regs->al);
212 switch (regs->al) {
213 case 0x35: roda_155f35(regs); break;
214 case 0x40: roda_155f40(regs); break;
215 default: handle_155fXX(regs); break;
216 }
217}
218
219static void
220kontron_155f35(struct bregs *regs)
221{
222 regs->ax = 0x005f;
223 regs->cl = BOOT_DISPLAY_CRT;
224 set_success(regs);
225}
226
227static void
228kontron_155f40(struct bregs *regs)
229{
230 u8 display_id;
231 display_id = 3;
232
233 regs->ax = 0x005f;
234 regs->cl = display_id;
235 set_success(regs);
236}
237
238static void
239kontron_155f(struct bregs *regs)
240{
241 dprintf(1, "Executing Kontron specific interrupt %02x.\n", regs->al);
242 switch (regs->al) {
243 case 0x35: kontron_155f35(regs); break;
244 case 0x40: kontron_155f40(regs); break;
245 default: handle_155fXX(regs); break;
246 }
247}
248
249static void
250getac_155f(struct bregs *regs)
251{
252 dprintf(1, "Executing Getac specific interrupt %02x.\n", regs->al);
253 switch (regs->al) {
254 default: handle_155fXX(regs); break;
255 }
256}
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400257
258/****************************************************************
259 * Entry and setup
260 ****************************************************************/
261
262// Main 16bit entry point
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400263void
264handle_155f(struct bregs *regs)
265{
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200266 int bdf, cbmb;
267
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400268 if (! CONFIG_VGAHOOKS)
269 goto fail;
270
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200271 cbmb = GET_GLOBAL(CBmainboard);
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400272
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200273 switch (cbmb) {
274 case KONTRON_986LCD_M:
275 kontron_155f(regs);
276 return;
277 case RODA_RK886EX:
278 roda_155f(regs);
279 return;
280 case GETAC_P470:
281 getac_155f(regs);
282 return;
283 case MAINBOARD_DEFAULT:
284 bdf = GET_GLOBAL(VGAbdf);
285 if (bdf < 0)
286 goto fail;
287
288 u16 vendor = pci_config_readw(bdf, PCI_VENDOR_ID);
289 if (vendor == PCI_VENDOR_ID_VIA) {
290 via_155f(regs);
291 return;
292 }
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400293 }
294
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400295fail:
296 handle_155fXX(regs);
297}
298
299// Setup
300void
301vgahook_setup(const char *vendor, const char *part)
302{
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200303 int i;
304
Kevin O'Connor22e1b912009-07-19 18:52:46 -0400305 if (! CONFIG_VGAHOOKS)
306 return;
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200307
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200308 for (i=0; i<(sizeof(mainboard_list) / sizeof(mainboard_list[0])); i++) {
309 if (!strcmp(vendor, mainboard_list[i].vendor) &&
310 !strcmp(part, mainboard_list[i].device)) {
Kevin O'Connor4d96edc2010-09-25 14:53:15 -0400311 printf("Found mainboard %s %s\n", vendor, part);
Stefan Reinauer8cb8ba52010-06-09 09:45:28 +0200312 CBmainboard = mainboard_list[i].type;
313 break;
314 }
315 }
Kevin O'Connorcbffa8e2008-08-17 11:11:07 -0400316}