diff options
-rw-r--r-- | CHANGELOG | 10 | ||||
-rw-r--r-- | drivers/pci_auto.c | 58 | ||||
-rw-r--r-- | include/pci.h | 4 |
3 files changed, 61 insertions, 11 deletions
@@ -2,6 +2,16 @@ Changes since U-Boot 1.1.4: ====================================================================== +* Added support for PCI prefetchable region and BARs + If a host controller sets up a region as prefetchable and + a device's BAR denotes it as prefetchable, allocate the + BAR into the prefetch region. + + If a BAR is prefetchable and no prefetchable region has + been setup by the controller we fall back to allocating + the BAR into the normally memory region. + Patch by Kumar Gala 11 Jan 2006 + * Add support for 28F256J3A flah (=> 64 MB) on PM520 board * Fix compiler problem with at91rm9200dk board. diff --git a/drivers/pci_auto.c b/drivers/pci_auto.c index 3302457a39..15f74328f0 100644 --- a/drivers/pci_auto.c +++ b/drivers/pci_auto.c @@ -77,6 +77,7 @@ int pciauto_region_allocate(struct pci_region* res, unsigned int size, unsigned void pciauto_setup_device(struct pci_controller *hose, pci_dev_t dev, int bars_num, struct pci_region *mem, + struct pci_region *prefetch, struct pci_region *io) { unsigned int bar_value, bar_response, bar_size; @@ -111,7 +112,10 @@ void pciauto_setup_device(struct pci_controller *hose, found_mem64 = 1; bar_size = ~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1; - bar_res = mem; + if (prefetch && (bar_response & PCI_BASE_ADDRESS_MEM_PREFETCH)) + bar_res = prefetch; + else + bar_res = mem; DEBUGF("PCI Autoconfig: BAR %d, Mem, size=0x%x, ", bar_nr, bar_size); } @@ -148,6 +152,7 @@ static void pciauto_prescan_setup_bridge(struct pci_controller *hose, pci_dev_t dev, int sub_bus) { struct pci_region *pci_mem = hose->pci_mem; + struct pci_region *pci_prefetch = hose->pci_prefetch; struct pci_region *pci_io = hose->pci_io; unsigned int cmdstat; @@ -169,6 +174,21 @@ static void pciauto_prescan_setup_bridge(struct pci_controller *hose, cmdstat |= PCI_COMMAND_MEMORY; } + if (pci_prefetch) { + /* Round memory allocator to 1MB boundary */ + pciauto_region_align(pci_prefetch, 0x100000); + + /* Set up memory and I/O filter limits, assume 32-bit I/O space */ + pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_BASE, + (pci_prefetch->bus_lower & 0xfff00000) >> 16); + + cmdstat |= PCI_COMMAND_MEMORY; + } else { + /* We don't support prefetchable memory for now, so disable */ + pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_BASE, 0x1000); + pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_LIMIT, 0x1000); + } + if (pci_io) { /* Round I/O allocator to 4KB boundary */ pciauto_region_align(pci_io, 0x1000); @@ -181,10 +201,6 @@ static void pciauto_prescan_setup_bridge(struct pci_controller *hose, cmdstat |= PCI_COMMAND_IO; } - /* We don't support prefetchable memory for now, so disable */ - pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_BASE, 0x1000); - pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_LIMIT, 0x1000); - /* Enable memory and I/O accesses, enable bus master */ pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat | PCI_COMMAND_MASTER); } @@ -193,6 +209,7 @@ static void pciauto_postscan_setup_bridge(struct pci_controller *hose, pci_dev_t dev, int sub_bus) { struct pci_region *pci_mem = hose->pci_mem; + struct pci_region *pci_prefetch = hose->pci_prefetch; struct pci_region *pci_io = hose->pci_io; /* Configure bus number registers */ @@ -206,6 +223,14 @@ static void pciauto_postscan_setup_bridge(struct pci_controller *hose, (pci_mem->bus_lower-1) >> 16); } + if (pci_prefetch) { + /* Round memory allocator to 1MB boundary */ + pciauto_region_align(pci_prefetch, 0x100000); + + pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_LIMIT, + (pci_prefetch->bus_lower-1) >> 16); + } + if (pci_io) { /* Round I/O allocator to 4KB boundary */ pciauto_region_align(pci_io, 0x1000); @@ -239,6 +264,11 @@ void pciauto_config_init(struct pci_controller *hose) hose->pci_mem->size < hose->regions[i].size) hose->pci_mem = hose->regions + i; break; + case (PCI_REGION_MEM | PCI_REGION_PREFETCH): + if (!hose->pci_prefetch || + hose->pci_prefetch->size < hose->regions[i].size) + hose->pci_prefetch = hose->regions + i; + break; } } @@ -251,6 +281,14 @@ void pciauto_config_init(struct pci_controller *hose) hose->pci_mem->bus_start + hose->pci_mem->size - 1); } + if (hose->pci_prefetch) { + pciauto_region_init(hose->pci_prefetch); + + DEBUGF("PCI Autoconfig: Prefetchable Memory region: [%lx-%lx]\n", + hose->pci_prefetch->bus_start, + hose->pci_prefetch->bus_start + hose->pci_prefetch->size - 1); + } + if (hose->pci_io) { pciauto_region_init(hose->pci_io); @@ -275,7 +313,7 @@ int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev) switch(class) { case PCI_CLASS_BRIDGE_PCI: hose->current_busno++; - pciauto_setup_device(hose, dev, 2, hose->pci_mem, hose->pci_io); + pciauto_setup_device(hose, dev, 2, hose->pci_mem, hose->pci_prefetch, hose->pci_io); DEBUGF("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_DEV(dev)); @@ -301,12 +339,12 @@ int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev) return sub_bus; } - pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_io); + pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_prefetch, hose->pci_io); break; case PCI_CLASS_BRIDGE_CARDBUS: /* just do a minimal setup of the bridge, let the OS take care of the rest */ - pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_io); + pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_prefetch, hose->pci_io); DEBUGF("PCI Autoconfig: Found P2CardBus bridge, device %d\n", PCI_DEV(dev)); @@ -328,11 +366,11 @@ int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev) * the PIMMR window to be allocated (BAR0 - 1MB size) */ DEBUGF("PCI Autoconfig: Broken bridge found, only minimal config\n"); - pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_io); + pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_prefetch, hose->pci_io); break; #endif default: - pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_io); + pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_prefetch, hose->pci_io); break; } diff --git a/include/pci.h b/include/pci.h index 8f19997559..f78a769bb1 100644 --- a/include/pci.h +++ b/include/pci.h @@ -309,6 +309,7 @@ struct pci_region { #define PCI_REGION_MEM 0x00000000 /* PCI memory space */ #define PCI_REGION_IO 0x00000001 /* PCI IO space */ #define PCI_REGION_TYPE 0x00000001 +#define PCI_REGION_PREFETCH 0x00000008 /* prefetchable PCI memory */ #define PCI_REGION_MEMORY 0x00000100 /* System memory */ #define PCI_REGION_RO 0x00000200 /* Read-only memory */ @@ -386,7 +387,7 @@ struct pci_controller { int (*write_dword)(struct pci_controller*, pci_dev_t, int where, u32); /* Used by auto config */ - struct pci_region *pci_mem, *pci_io; + struct pci_region *pci_mem, *pci_io, *pci_prefetch; /* Used by ppc405 autoconfig*/ struct pci_region *pci_fb; @@ -472,6 +473,7 @@ extern int pciauto_region_allocate(struct pci_region* res, unsigned int size, un extern void pciauto_setup_device(struct pci_controller *hose, pci_dev_t dev, int bars_num, struct pci_region *mem, + struct pci_region *prefetch, struct pci_region *io); int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev); |