blob: 44c98d130c7d330381f2382522895544bed1570f [file] [log] [blame]
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2001 Ronald G. Minnich
5 * Copyright (C) 2005 Nick.Barker9@btinternet.com
6 * Copyright (C) 2007-2009 coresystems GmbH
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
Stefan Reinauer6c641ee2009-09-23 21:52:45 +000019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000020 */
21
22#include <device/pci.h>
23#include <device/pci_ids.h>
24#include <device/pci_ops.h>
25#include <string.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000026#include <console/console.h>
27#include <arch/io.h>
Stefan Reinauer42dc7212009-10-24 00:47:07 +000028#include <arch/registers.h>
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000029
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000030enum {
Mark Marshalld08e69d2009-11-05 09:03:04 +000031 PCIBIOS_CHECK = 0xb101,
32 PCIBIOS_FINDDEV = 0xb102,
33 PCIBIOS_READCONFBYTE = 0xb108,
34 PCIBIOS_READCONFWORD = 0xb109,
35 PCIBIOS_READCONFDWORD = 0xb10a,
36 PCIBIOS_WRITECONFBYTE = 0xb10b,
37 PCIBIOS_WRITECONFWORD = 0xb10c,
38 PCIBIOS_WRITECONFDWORD = 0xb10d
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000039};
40
41// errors go in AH. Just set these up so that word assigns
42// will work. KISS.
43enum {
Mark Marshalld08e69d2009-11-05 09:03:04 +000044 PCIBIOS_SUCCESSFUL = 0x0000,
45 PCIBIOS_UNSUPPORTED = 0x8100,
46 PCIBIOS_BADVENDOR = 0x8300,
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000047 PCIBIOS_NODEV = 0x8600,
48 PCIBIOS_BADREG = 0x8700
49};
50
Maciej Pijankaea921852009-10-27 14:29:29 +000051int int12_handler(struct eregs *regs);
52int int1a_handler(struct eregs *regs);
53int int15_handler(struct eregs *regs);
54
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000055int int12_handler(struct eregs *regs)
56{
57 regs->eax = 64 * 1024;
58 return 0;
59}
60
Stefan Reinauer607cdf62010-04-26 12:08:51 +000061#define PCI_CONFIG_SPACE_TYPE1 (1 << 0)
62#define PCI_CONFIG_SPACE_TYPE2 (1 << 1)
63#define PCI_SPECIAL_CYCLE_TYPE1 (1 << 4)
64#define PCI_SPECIAL_CYCLE_TYPE2 (1 << 5)
65
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000066int int1a_handler(struct eregs *regs)
67{
Mark Marshalld08e69d2009-11-05 09:03:04 +000068 unsigned short func = (unsigned short)regs->eax;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000069 int retval = 0;
70 unsigned short devid, vendorid, devfn;
71 /* Use short to get rid of gabage in upper half of 32-bit register */
72 short devindex;
73 unsigned char bus;
74 struct device *dev;
Stefan Reinauer46634e72009-11-05 12:44:50 +000075 u32 dword;
76 u16 word;
77 u8 byte, reg;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000078
Mark Marshalld08e69d2009-11-05 09:03:04 +000079 switch (func) {
80 case PCIBIOS_CHECK:
81 regs->edx = 0x20494350; /* ' ICP' */
Stefan Reinauer607cdf62010-04-26 12:08:51 +000082 regs->eax &= 0xffff0000; /* Clear AH / AL */
83 regs->eax |= PCI_CONFIG_SPACE_TYPE1 | PCI_SPECIAL_CYCLE_TYPE1;
84 // last bus in the system. Hard code to 255 for now.
85 // dev_enumerate() does not seem to tell us (publically)
86 regs->ecx = 0xff;
Mark Marshalld08e69d2009-11-05 09:03:04 +000087 regs->edi = 0x00000000; /* protected mode entry */
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000088 retval = 0;
89 break;
Mark Marshalld08e69d2009-11-05 09:03:04 +000090 case PCIBIOS_FINDDEV:
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000091 devid = regs->ecx;
92 vendorid = regs->edx;
93 devindex = regs->esi;
94 dev = 0;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000095 while ((dev = dev_find_device(vendorid, devid, dev))) {
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000096 if (devindex <= 0)
97 break;
98 devindex--;
99 }
100 if (dev) {
101 unsigned short busdevfn;
102 regs->eax = 0;
103 // busnum is an unsigned char;
104 // devfn is an int, so we mask it off.
105 busdevfn = (dev->bus->secondary << 8)
Mark Marshalld08e69d2009-11-05 09:03:04 +0000106 | (dev->path.pci.devfn & 0xff);
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000107 printk(BIOS_DEBUG, "0x%x: return 0x%x\n", func, busdevfn);
108 regs->ebx = busdevfn;
109 retval = 0;
110 } else {
111 regs->eax = PCIBIOS_NODEV;
112 retval = -1;
113 }
Mark Marshalld08e69d2009-11-05 09:03:04 +0000114 break;
115 case PCIBIOS_READCONFDWORD:
116 case PCIBIOS_READCONFWORD:
117 case PCIBIOS_READCONFBYTE:
118 case PCIBIOS_WRITECONFDWORD:
119 case PCIBIOS_WRITECONFWORD:
120 case PCIBIOS_WRITECONFBYTE:
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000121 devfn = regs->ebx & 0xff;
122 bus = regs->ebx >> 8;
123 reg = regs->edi;
124 dev = dev_find_slot(bus, devfn);
Mark Marshalld08e69d2009-11-05 09:03:04 +0000125 if (!dev) {
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000126 printk(BIOS_DEBUG, "0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, bus, devfn);
Stefan Reinauer607cdf62010-04-26 12:08:51 +0000127 // Or are we supposed to return PCIBIOS_NODEV?
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000128 regs->eax = PCIBIOS_BADREG;
129 retval = -1;
Mark Marshalld08e69d2009-11-05 09:03:04 +0000130 return retval;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000131 }
Mark Marshalld08e69d2009-11-05 09:03:04 +0000132 switch (func) {
133 case PCIBIOS_READCONFBYTE:
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000134 byte = pci_read_config8(dev, reg);
135 regs->ecx = byte;
136 break;
Mark Marshalld08e69d2009-11-05 09:03:04 +0000137 case PCIBIOS_READCONFWORD:
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000138 word = pci_read_config16(dev, reg);
139 regs->ecx = word;
140 break;
Mark Marshalld08e69d2009-11-05 09:03:04 +0000141 case PCIBIOS_READCONFDWORD:
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000142 dword = pci_read_config32(dev, reg);
143 regs->ecx = dword;
144 break;
Mark Marshalld08e69d2009-11-05 09:03:04 +0000145 case PCIBIOS_WRITECONFBYTE:
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000146 byte = regs->ecx;
147 pci_write_config8(dev, reg, byte);
148 break;
Mark Marshalld08e69d2009-11-05 09:03:04 +0000149 case PCIBIOS_WRITECONFWORD:
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000150 word = regs->ecx;
151 pci_write_config16(dev, reg, word);
152 break;
Mark Marshalld08e69d2009-11-05 09:03:04 +0000153 case PCIBIOS_WRITECONFDWORD:
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000154 dword = regs->ecx;
155 pci_write_config32(dev, reg, dword);
156 break;
157 }
158
Myles Watson6c9bc012010-09-07 22:30:15 +0000159#if CONFIG_REALMODE_DEBUG
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000160 printk(BIOS_DEBUG, "0x%x: bus %d devfn 0x%x reg 0x%x val 0x%x\n",
161 func, bus, devfn, reg, regs->ecx);
Myles Watson6c9bc012010-09-07 22:30:15 +0000162#endif
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000163 regs->eax = 0;
164 retval = 0;
Mark Marshalld08e69d2009-11-05 09:03:04 +0000165 break;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000166 default:
Mark Marshalld08e69d2009-11-05 09:03:04 +0000167 printk(BIOS_ERR, "UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func);
168 retval = -1;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000169 break;
170 }
171
172 return retval;
173}
174
175int int15_handler(struct eregs *regs)
176{
177 int res = -1;
178
Stefan Reinauer607cdf62010-04-26 12:08:51 +0000179 /* This int15 handler is Intel IGD. specific. Other chipsets need other
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000180 * handlers. The right way to do this is to move this handler code into
181 * the mainboard or northbridge code.
Stefan Reinauer607cdf62010-04-26 12:08:51 +0000182 * TODO: completely move to mainboards / chipsets.
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000183 */
184 switch (regs->eax & 0xffff) {
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000185 /* And now Intel IGD code */
Stefan Reinauer074356e2009-10-25 19:50:47 +0000186#define BOOT_DISPLAY_DEFAULT 0
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000187#define BOOT_DISPLAY_CRT (1 << 0)
188#define BOOT_DISPLAY_TV (1 << 1)
189#define BOOT_DISPLAY_EFP (1 << 2)
190#define BOOT_DISPLAY_LCD (1 << 3)
191#define BOOT_DISPLAY_CRT2 (1 << 4)
192#define BOOT_DISPLAY_TV2 (1 << 5)
193#define BOOT_DISPLAY_EFP2 (1 << 6)
194#define BOOT_DISPLAY_LCD2 (1 << 7)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000195 case 0x5f35:
196 regs->eax = 0x5f;
Stefan Reinauer074356e2009-10-25 19:50:47 +0000197 regs->ecx = BOOT_DISPLAY_DEFAULT;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000198 res = 0;
199 break;
200 case 0x5f40:
201 regs->eax = 0x5f;
202 regs->ecx = 3; // This is mainboard specific
203 printk(BIOS_DEBUG, "DISPLAY=%x\n", regs->ecx);
204 res = 0;
205 break;
206 default:
Stefan Reinauer14e22772010-04-27 06:56:47 +0000207 printk(BIOS_DEBUG, "Unknown INT15 function %04x!\n",
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000208 regs->eax & 0xffff);
209 }
210
211 return res;
212}
213