/* PCI (Static) Configuration Library * * COPYRIGHT (c) 2010 Cobham Gaisler AB. * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.org/license/LICENSE. */ /* * The Host Bridge bus must be declared by user. It contains the static * configuration used to setup the devices/functions. */ /* Configure headers */ #define PCI_CFG_STATIC_LIB #include #include #include #include #include "pci_internal.h" #define PCI_CFG_R8(dev, args...) pci_cfg_r8(dev, args) #define PCI_CFG_R16(dev, args...) pci_cfg_r16(dev, args) #define PCI_CFG_R32(dev, args...) pci_cfg_r32(dev, args) #define PCI_CFG_W8(dev, args...) pci_cfg_w8(dev, args) #define PCI_CFG_W16(dev, args...) pci_cfg_w16(dev, args) #define PCI_CFG_W32(dev, args...) pci_cfg_w32(dev, args) /* Enumrate one bus if device is a bridge, and all it's subordinate buses */ static int pci_init_dev(struct pci_dev *dev, void *unused) { uint32_t tmp; uint16_t tmp16, cmd; struct pci_bus *bridge; int maxbars, i, romofs; pci_dev_t pcidev = dev->busdevfun; struct pci_res *res; /* Init Device */ /* Set command to reset values, it disables bus * mastering and address responses. */ PCI_CFG_W16(pcidev, PCIR_COMMAND, 0); /* Clear any already set status bits */ PCI_CFG_W16(pcidev, PCIR_STATUS, 0xf900); /* Set latency timer to 64 */ PCI_CFG_W8(pcidev, PCIR_LATTIMER, 64); /* Set System IRQ of PIN */ PCI_CFG_W8(pcidev, PCIR_INTLINE, dev->sysirq); cmd = dev->command; if ((dev->flags & PCI_DEV_BRIDGE) == 0) { /* Disable Cardbus CIS Pointer */ PCI_CFG_W32(pcidev, PCIR_CIS, 0); romofs = PCIR_BIOS; maxbars = 6; } else { /* Init Bridge */ /* Configure bridge (no support for 64-bit) */ PCI_CFG_W32(pcidev, PCIR_PMBASEH_1, 0); PCI_CFG_W32(pcidev, PCIR_PMLIMITH_1, 0); bridge = (struct pci_bus *)dev; tmp = (64 << 24) | (bridge->sord << 16) | (bridge->num << 8) | bridge->pri; PCI_CFG_W32(pcidev, PCIR_PRIBUS_1, tmp); /*** Setup I/O Bridge Window ***/ res = &dev->resources[BRIDGE_RES_IO]; if (res->size > 0) { tmp16 = ((res->end-1) & 0x0000f000) | ((res->start & 0x0000f000) >> 8); tmp = ((res->end-1) & 0xffff0000) | (res->start >> 16); cmd |= PCIM_CMD_PORTEN; } else { tmp16 = 0x00ff; tmp = 0; } /* I/O Limit and Base */ PCI_CFG_W16(pcidev, PCIR_IOBASEL_1, tmp16); PCI_CFG_W32(pcidev, PCIR_IOBASEH_1, tmp); /*** Setup MEMIO Bridge Window ***/ res = &dev->resources[BRIDGE_RES_MEMIO]; if (res->size > 0) { tmp = ((res->end-1) & 0xffff0000) | (res->start >> 16); cmd |= PCIM_CMD_MEMEN; } else { tmp = 0x0000ffff; } /* MEMIO Limit and Base */ PCI_CFG_W32(pcidev, PCIR_MEMBASE_1, tmp); /*** Setup MEM Bridge Window ***/ res = &dev->resources[BRIDGE_RES_MEM]; if (res->size > 0) { tmp = ((res->end-1) & 0xffff0000) | (res->start >> 16); cmd |= PCIM_CMD_MEMEN; } else { tmp = 0x0000ffff; } /* MEM Limit and Base */ PCI_CFG_W32(pcidev, PCIR_PMBASEL_1, tmp); /* 64-bit space not supported */ PCI_CFG_W32(pcidev, PCIR_PMBASEH_1, 0); PCI_CFG_W32(pcidev, PCIR_PMLIMITH_1, 0); cmd |= PCIM_CMD_BUSMASTEREN; romofs = PCIR_BIOS_1; maxbars = 2; } /* Init BARs */ for (i = 0; i < maxbars; i++) { res = &dev->resources[i]; if (res->flags & PCI_RES_TYPE_MASK) { PCI_CFG_W32(pcidev, PCIR_BAR(0) + 4*i, res->start); if ((res->flags & PCI_RES_TYPE_MASK) == PCI_RES_IO) cmd |= PCIM_CMD_PORTEN; else cmd |= PCIM_CMD_MEMEN; } } res = &dev->resources[DEV_RES_ROM]; if (res->flags & PCI_RES_TYPE_MASK) { PCI_CFG_W32(pcidev, romofs, res->start|PCIM_BIOS_ENABLE); cmd |= PCIM_CMD_MEMEN; } PCI_CFG_W16(pcidev, PCIR_COMMAND, cmd); return 0; } /* Assume that user has defined static setup array in pci_hb */ int pci_config_static(void) { pci_bus_cnt = pci_hb.sord + 1; pci_system_type = PCI_SYSTEM_HOST; /* Init all PCI devices according to depth-first search algorithm */ return pci_for_each_dev(pci_init_dev, NULL); }