|
|
1.1 root 1: // Initialize PCI devices (on emulators)
2: //
3: // Copyright (C) 2008 Kevin O'Connor <[email protected]>
4: // Copyright (C) 2006 Fabrice Bellard
5: //
6: // This file may be distributed under the terms of the GNU LGPLv3 license.
7:
8: #include "util.h" // dprintf
9: #include "pci.h" // pci_config_readl
10: #include "biosvar.h" // GET_EBDA
11: #include "pci_ids.h" // PCI_VENDOR_ID_INTEL
12: #include "pci_regs.h" // PCI_COMMAND
1.1.1.4 ! root 13: #include "dev-i440fx.h"
1.1 root 14:
15: #define PCI_ROM_SLOT 6
16: #define PCI_NUM_REGIONS 7
17:
1.1.1.4 ! root 18: static void pci_bios_init_device_in_bus(int bus);
! 19:
1.1 root 20: static u32 pci_bios_io_addr;
21: static u32 pci_bios_mem_addr;
1.1.1.4 ! root 22: static u32 pci_bios_prefmem_addr;
1.1 root 23: /* host irqs corresponding to PCI irqs A-D */
1.1.1.4 ! root 24: const u8 pci_irqs[4] = {
1.1 root 25: 10, 10, 11, 11
26: };
27:
1.1.1.4 ! root 28: static u32 pci_bar(u16 bdf, int region_num)
! 29: {
! 30: if (region_num != PCI_ROM_SLOT) {
! 31: return PCI_BASE_ADDRESS_0 + region_num * 4;
! 32: }
! 33:
! 34: #define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80
! 35: u8 type = pci_config_readb(bdf, PCI_HEADER_TYPE);
! 36: type &= ~PCI_HEADER_TYPE_MULTI_FUNCTION;
! 37: return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS;
! 38: }
! 39:
1.1 root 40: static void pci_set_io_region_addr(u16 bdf, int region_num, u32 addr)
41: {
42: u32 ofs, old_addr;
43:
1.1.1.4 ! root 44: ofs = pci_bar(bdf, region_num);
1.1 root 45:
46: old_addr = pci_config_readl(bdf, ofs);
47:
48: pci_config_writel(bdf, ofs, addr);
49: dprintf(1, "region %d: 0x%08x\n", region_num, addr);
50: }
51:
1.1.1.4 ! root 52: /*
! 53: * return value
! 54: * 0: 32bit BAR
! 55: * non 0: 64bit BAR
! 56: */
! 57: static int pci_bios_allocate_region(u16 bdf, int region_num)
! 58: {
! 59: u32 *paddr;
! 60: u32 ofs = pci_bar(bdf, region_num);
! 61:
! 62: u32 old = pci_config_readl(bdf, ofs);
! 63: u32 mask;
! 64: if (region_num == PCI_ROM_SLOT) {
! 65: mask = PCI_ROM_ADDRESS_MASK;
! 66: pci_config_writel(bdf, ofs, mask);
! 67: } else {
! 68: if (old & PCI_BASE_ADDRESS_SPACE_IO)
! 69: mask = PCI_BASE_ADDRESS_IO_MASK;
! 70: else
! 71: mask = PCI_BASE_ADDRESS_MEM_MASK;
! 72: pci_config_writel(bdf, ofs, ~0);
! 73: }
! 74: u32 val = pci_config_readl(bdf, ofs);
! 75: pci_config_writel(bdf, ofs, old);
! 76:
! 77: u32 size = (~(val & mask)) + 1;
! 78: if (val != 0) {
! 79: if (val & PCI_BASE_ADDRESS_SPACE_IO) {
! 80: paddr = &pci_bios_io_addr;
! 81: if (ALIGN(*paddr, size) + size >= 64 * 1024) {
! 82: dprintf(1,
! 83: "io region of (bdf 0x%x bar %d) can't be mapped.\n",
! 84: bdf, region_num);
! 85: size = 0;
! 86: }
! 87: } else if ((val & PCI_BASE_ADDRESS_MEM_PREFETCH) &&
! 88: /* keep behaviour on bus = 0 */
! 89: pci_bdf_to_bus(bdf) != 0 &&
! 90: /* If pci_bios_prefmem_addr == 0, keep old behaviour */
! 91: pci_bios_prefmem_addr != 0) {
! 92: paddr = &pci_bios_prefmem_addr;
! 93: if (ALIGN(*paddr, size) + size >= BUILD_PCIPREFMEM_END) {
! 94: dprintf(1,
! 95: "prefmem region of (bdf 0x%x bar %d) can't be mapped. "
! 96: "decrease BUILD_PCIMEM_SIZE and recompile. size %x\n",
! 97: bdf, region_num, BUILD_PCIPREFMEM_SIZE);
! 98: size = 0;
! 99: }
! 100: } else {
! 101: paddr = &pci_bios_mem_addr;
! 102: if (ALIGN(*paddr, size) + size >= BUILD_PCIMEM_END) {
! 103: dprintf(1,
! 104: "mem region of (bdf 0x%x bar %d) can't be mapped. "
! 105: "increase BUILD_PCIMEM_SIZE and recompile. size %x\n",
! 106: bdf, region_num, BUILD_PCIMEM_SIZE);
! 107: size = 0;
! 108: }
! 109: }
! 110: if (size > 0) {
! 111: *paddr = ALIGN(*paddr, size);
! 112: pci_set_io_region_addr(bdf, region_num, *paddr);
! 113: *paddr += size;
! 114: }
! 115: }
! 116:
! 117: int is_64bit = !(val & PCI_BASE_ADDRESS_SPACE_IO) &&
! 118: (val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64;
! 119: if (is_64bit) {
! 120: if (size > 0) {
! 121: pci_config_writel(bdf, ofs + 4, 0);
! 122: } else {
! 123: pci_config_writel(bdf, ofs + 4, ~0);
! 124: }
! 125: }
! 126: return is_64bit;
! 127: }
! 128:
! 129: void pci_bios_allocate_regions(u16 bdf, void *arg)
! 130: {
! 131: int i;
! 132: for (i = 0; i < PCI_NUM_REGIONS; i++) {
! 133: int is_64bit = pci_bios_allocate_region(bdf, i);
! 134: if (is_64bit){
! 135: i++;
! 136: }
! 137: }
! 138: }
! 139:
1.1 root 140: /* return the global irq number corresponding to a given device irq
141: pin. We could also use the bus number to have a more precise
142: mapping. */
143: static int pci_slot_get_pirq(u16 bdf, int irq_num)
144: {
145: int slot_addend = pci_bdf_to_dev(bdf) - 1;
146: return (irq_num + slot_addend) & 3;
147: }
148:
1.1.1.4 ! root 149: static const struct pci_device_id pci_isa_bridge_tbl[] = {
! 150: /* PIIX3/PIIX4 PCI to ISA bridge */
! 151: PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0,
! 152: piix_isa_bridge_init),
! 153: PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
! 154: piix_isa_bridge_init),
! 155:
! 156: PCI_DEVICE_END
! 157: };
! 158:
! 159: #define PCI_IO_ALIGN 4096
! 160: #define PCI_IO_SHIFT 8
! 161: #define PCI_MEMORY_ALIGN (1UL << 20)
! 162: #define PCI_MEMORY_SHIFT 16
! 163: #define PCI_PREF_MEMORY_ALIGN (1UL << 20)
! 164: #define PCI_PREF_MEMORY_SHIFT 16
! 165:
! 166: static void pci_bios_init_device_bridge(u16 bdf, void *arg)
1.1 root 167: {
1.1.1.4 ! root 168: pci_bios_allocate_region(bdf, 0);
! 169: pci_bios_allocate_region(bdf, 1);
! 170: pci_bios_allocate_region(bdf, PCI_ROM_SLOT);
! 171:
! 172: u32 io_old = pci_bios_io_addr;
! 173: u32 mem_old = pci_bios_mem_addr;
! 174: u32 prefmem_old = pci_bios_prefmem_addr;
! 175:
! 176: /* IO BASE is assumed to be 16 bit */
! 177: pci_bios_io_addr = ALIGN(pci_bios_io_addr, PCI_IO_ALIGN);
! 178: pci_bios_mem_addr = ALIGN(pci_bios_mem_addr, PCI_MEMORY_ALIGN);
! 179: pci_bios_prefmem_addr =
! 180: ALIGN(pci_bios_prefmem_addr, PCI_PREF_MEMORY_ALIGN);
! 181:
! 182: u32 io_base = pci_bios_io_addr;
! 183: u32 mem_base = pci_bios_mem_addr;
! 184: u32 prefmem_base = pci_bios_prefmem_addr;
! 185:
! 186: u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS);
! 187: if (secbus > 0) {
! 188: pci_bios_init_device_in_bus(secbus);
! 189: }
1.1 root 190:
1.1.1.4 ! root 191: pci_bios_io_addr = ALIGN(pci_bios_io_addr, PCI_IO_ALIGN);
! 192: pci_bios_mem_addr = ALIGN(pci_bios_mem_addr, PCI_MEMORY_ALIGN);
! 193: pci_bios_prefmem_addr =
! 194: ALIGN(pci_bios_prefmem_addr, PCI_PREF_MEMORY_ALIGN);
! 195:
! 196: u32 io_end = pci_bios_io_addr;
! 197: if (io_end == io_base) {
! 198: pci_bios_io_addr = io_old;
! 199: io_base = 0xffff;
! 200: io_end = 1;
1.1 root 201: }
1.1.1.4 ! root 202: pci_config_writeb(bdf, PCI_IO_BASE, io_base >> PCI_IO_SHIFT);
! 203: pci_config_writew(bdf, PCI_IO_BASE_UPPER16, 0);
! 204: pci_config_writeb(bdf, PCI_IO_LIMIT, (io_end - 1) >> PCI_IO_SHIFT);
! 205: pci_config_writew(bdf, PCI_IO_LIMIT_UPPER16, 0);
! 206:
! 207: u32 mem_end = pci_bios_mem_addr;
! 208: if (mem_end == mem_base) {
! 209: pci_bios_mem_addr = mem_old;
! 210: mem_base = 0xffffffff;
! 211: mem_end = 1;
! 212: }
! 213: pci_config_writew(bdf, PCI_MEMORY_BASE, mem_base >> PCI_MEMORY_SHIFT);
! 214: pci_config_writew(bdf, PCI_MEMORY_LIMIT, (mem_end -1) >> PCI_MEMORY_SHIFT);
! 215:
! 216: u32 prefmem_end = pci_bios_prefmem_addr;
! 217: if (prefmem_end == prefmem_base) {
! 218: pci_bios_prefmem_addr = prefmem_old;
! 219: prefmem_base = 0xffffffff;
! 220: prefmem_end = 1;
! 221: }
! 222: pci_config_writew(bdf, PCI_PREF_MEMORY_BASE,
! 223: prefmem_base >> PCI_PREF_MEMORY_SHIFT);
! 224: pci_config_writew(bdf, PCI_PREF_MEMORY_LIMIT,
! 225: (prefmem_end - 1) >> PCI_PREF_MEMORY_SHIFT);
! 226: pci_config_writel(bdf, PCI_PREF_BASE_UPPER32, 0);
! 227: pci_config_writel(bdf, PCI_PREF_LIMIT_UPPER32, 0);
! 228:
! 229: dprintf(1, "PCI: br io = [0x%x, 0x%x)\n", io_base, io_end);
! 230: dprintf(1, "PCI: br mem = [0x%x, 0x%x)\n", mem_base, mem_end);
! 231: dprintf(1, "PCI: br pref = [0x%x, 0x%x)\n", prefmem_base, prefmem_end);
! 232:
! 233: u16 cmd = pci_config_readw(bdf, PCI_COMMAND);
! 234: cmd &= ~PCI_COMMAND_IO;
! 235: if (io_end > io_base) {
! 236: cmd |= PCI_COMMAND_IO;
! 237: }
! 238: cmd &= ~PCI_COMMAND_MEMORY;
! 239: if (mem_end > mem_base || prefmem_end > prefmem_base) {
! 240: cmd |= PCI_COMMAND_MEMORY;
! 241: }
! 242: cmd |= PCI_COMMAND_MASTER;
! 243: pci_config_writew(bdf, PCI_COMMAND, cmd);
! 244:
! 245: pci_config_maskw(bdf, PCI_BRIDGE_CONTROL, 0, PCI_BRIDGE_CTL_SERR);
! 246: }
! 247:
! 248: static void storage_ide_init(u16 bdf, void *arg)
! 249: {
! 250: /* IDE: we map it as in ISA mode */
! 251: pci_set_io_region_addr(bdf, 0, PORT_ATA1_CMD_BASE);
! 252: pci_set_io_region_addr(bdf, 1, PORT_ATA1_CTRL_BASE);
! 253: pci_set_io_region_addr(bdf, 2, PORT_ATA2_CMD_BASE);
! 254: pci_set_io_region_addr(bdf, 3, PORT_ATA2_CTRL_BASE);
! 255: }
! 256:
! 257: static void pic_ibm_init(u16 bdf, void *arg)
! 258: {
! 259: /* PIC, IBM, MPIC & MPIC2 */
! 260: pci_set_io_region_addr(bdf, 0, 0x80800000 + 0x00040000);
1.1 root 261: }
262:
1.1.1.4 ! root 263: static void apple_macio_init(u16 bdf, void *arg)
! 264: {
! 265: /* macio bridge */
! 266: pci_set_io_region_addr(bdf, 0, 0x80800000);
! 267: }
! 268:
! 269: static const struct pci_device_id pci_class_tbl[] = {
! 270: /* STORAGE IDE */
! 271: PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1,
! 272: PCI_CLASS_STORAGE_IDE, piix_ide_init),
! 273: PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB,
! 274: PCI_CLASS_STORAGE_IDE, piix_ide_init),
! 275: PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE,
! 276: storage_ide_init),
! 277:
! 278: /* PIC, IBM, MIPC & MPIC2 */
! 279: PCI_DEVICE_CLASS(PCI_VENDOR_ID_IBM, 0x0046, PCI_CLASS_SYSTEM_PIC,
! 280: pic_ibm_init),
! 281: PCI_DEVICE_CLASS(PCI_VENDOR_ID_IBM, 0xFFFF, PCI_CLASS_SYSTEM_PIC,
! 282: pic_ibm_init),
! 283:
! 284: /* 0xff00 */
! 285: PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0017, 0xff00, apple_macio_init),
! 286: PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0022, 0xff00, apple_macio_init),
! 287:
! 288: /* PCI bridge */
! 289: PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_BRIDGE_PCI,
! 290: pci_bios_init_device_bridge),
! 291:
! 292: /* default */
! 293: PCI_DEVICE(PCI_ANY_ID, PCI_ANY_ID, pci_bios_allocate_regions),
! 294:
! 295: PCI_DEVICE_END,
! 296: };
! 297:
! 298: static const struct pci_device_id pci_device_tbl[] = {
! 299: /* PIIX4 Power Management device (for ACPI) */
! 300: PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
! 301: piix4_pm_init),
! 302:
! 303: PCI_DEVICE_END,
! 304: };
! 305:
1.1 root 306: static void pci_bios_init_device(u16 bdf)
307: {
1.1.1.4 ! root 308: int pin, pic_irq, vendor_id, device_id;
1.1 root 309:
310: vendor_id = pci_config_readw(bdf, PCI_VENDOR_ID);
311: device_id = pci_config_readw(bdf, PCI_DEVICE_ID);
312: dprintf(1, "PCI: bus=%d devfn=0x%02x: vendor_id=0x%04x device_id=0x%04x\n"
313: , pci_bdf_to_bus(bdf), pci_bdf_to_devfn(bdf), vendor_id, device_id);
1.1.1.4 ! root 314: pci_init_device(pci_class_tbl, bdf, NULL);
1.1 root 315:
316: /* enable memory mappings */
317: pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
318:
319: /* map the interrupt */
320: pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN);
321: if (pin != 0) {
322: pin = pci_slot_get_pirq(bdf, pin - 1);
323: pic_irq = pci_irqs[pin];
324: pci_config_writeb(bdf, PCI_INTERRUPT_LINE, pic_irq);
325: }
326:
1.1.1.4 ! root 327: pci_init_device(pci_device_tbl, bdf, NULL);
! 328: }
! 329:
! 330: static void pci_bios_init_device_in_bus(int bus)
! 331: {
! 332: int bdf, max;
! 333: foreachpci_in_bus(bdf, max, bus) {
! 334: pci_bios_init_device(bdf);
1.1 root 335: }
336: }
337:
1.1.1.4 ! root 338: static void
! 339: pci_bios_init_bus_rec(int bus, u8 *pci_bus)
! 340: {
! 341: int bdf, max;
! 342: u16 class;
! 343:
! 344: dprintf(1, "PCI: %s bus = 0x%x\n", __func__, bus);
! 345:
! 346: /* prevent accidental access to unintended devices */
! 347: foreachpci_in_bus(bdf, max, bus) {
! 348: class = pci_config_readw(bdf, PCI_CLASS_DEVICE);
! 349: if (class == PCI_CLASS_BRIDGE_PCI) {
! 350: pci_config_writeb(bdf, PCI_SECONDARY_BUS, 255);
! 351: pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, 0);
! 352: }
! 353: }
! 354:
! 355: foreachpci_in_bus(bdf, max, bus) {
! 356: class = pci_config_readw(bdf, PCI_CLASS_DEVICE);
! 357: if (class != PCI_CLASS_BRIDGE_PCI) {
! 358: continue;
! 359: }
! 360: dprintf(1, "PCI: %s bdf = 0x%x\n", __func__, bdf);
! 361:
! 362: u8 pribus = pci_config_readb(bdf, PCI_PRIMARY_BUS);
! 363: if (pribus != bus) {
! 364: dprintf(1, "PCI: primary bus = 0x%x -> 0x%x\n", pribus, bus);
! 365: pci_config_writeb(bdf, PCI_PRIMARY_BUS, bus);
! 366: } else {
! 367: dprintf(1, "PCI: primary bus = 0x%x\n", pribus);
! 368: }
! 369:
! 370: u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS);
! 371: (*pci_bus)++;
! 372: if (*pci_bus != secbus) {
! 373: dprintf(1, "PCI: secondary bus = 0x%x -> 0x%x\n",
! 374: secbus, *pci_bus);
! 375: secbus = *pci_bus;
! 376: pci_config_writeb(bdf, PCI_SECONDARY_BUS, secbus);
! 377: } else {
! 378: dprintf(1, "PCI: secondary bus = 0x%x\n", secbus);
! 379: }
! 380:
! 381: /* set to max for access to all subordinate buses.
! 382: later set it to accurate value */
! 383: u8 subbus = pci_config_readb(bdf, PCI_SUBORDINATE_BUS);
! 384: pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, 255);
! 385:
! 386: pci_bios_init_bus_rec(secbus, pci_bus);
! 387:
! 388: if (subbus != *pci_bus) {
! 389: dprintf(1, "PCI: subordinate bus = 0x%x -> 0x%x\n",
! 390: subbus, *pci_bus);
! 391: subbus = *pci_bus;
! 392: } else {
! 393: dprintf(1, "PCI: subordinate bus = 0x%x\n", subbus);
! 394: }
! 395: pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, subbus);
! 396: }
! 397: }
! 398:
! 399: static void
! 400: pci_bios_init_bus(void)
! 401: {
! 402: u8 pci_bus = 0;
! 403: pci_bios_init_bus_rec(0 /* host bus */, &pci_bus);
! 404: }
! 405:
1.1 root 406: void
407: pci_setup(void)
408: {
409: if (CONFIG_COREBOOT)
410: // Already done by coreboot.
411: return;
412:
413: dprintf(3, "pci setup\n");
414:
415: pci_bios_io_addr = 0xc000;
1.1.1.3 root 416: pci_bios_mem_addr = BUILD_PCIMEM_START;
1.1.1.4 ! root 417: pci_bios_prefmem_addr = BUILD_PCIPREFMEM_START;
! 418:
! 419: pci_bios_init_bus();
1.1 root 420:
421: int bdf, max;
422: foreachpci(bdf, max) {
1.1.1.4 ! root 423: pci_init_device(pci_isa_bridge_tbl, bdf, NULL);
1.1 root 424: }
1.1.1.4 ! root 425: pci_bios_init_device_in_bus(0 /* host bus */);
1.1 root 426: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.