aboutsummaryrefslogtreecommitdiff
path: root/src/fw/pciinit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fw/pciinit.c')
-rw-r--r--src/fw/pciinit.c81
1 files changed, 76 insertions, 5 deletions
diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c
index 4c16ea0..d79fb56 100644
--- a/src/fw/pciinit.c
+++ b/src/fw/pciinit.c
@@ -509,6 +509,12 @@ static void mch_mem_addr_setup(struct pci_device *dev, void *arg)
pci_io_low_end = acpi_pm_base;
}
+/*
+ * parisc: If mmio bar is bigger than this size, map the bar it into the
+ * directed ELMMIO instead of the distributed LMMIO region.
+ */
+#define PARISC_MMIO_LIMIT 0x10000
+
#if CONFIG_PARISC
static int dino_pci_slot_get_irq(struct pci_device *pci, int pin)
{
@@ -536,8 +542,64 @@ static void dino_mem_addr_setup(struct pci_device *dev, void *arg)
/* setup io address space */
pci_io_low_end = 0xa000;
}
+
+static int astro_pci_slot_get_irq(struct pci_device *pci, int pin)
+{
+ int bus = pci_bdf_to_bus(pci->bdf);
+ int slot = pci_bdf_to_dev(pci->bdf);
+ return (bus + 1) * 4 + (slot & 0x03);
+}
+
+static void astro_mem_addr_setup(struct pci_device *dev, void *arg)
+{
+ pcimem_start = LMMIO_DIST_BASE_ADDR;
+ pcimem_end = pcimem_start + LMMIO_DIST_BASE_SIZE / ROPES_PER_IOC;
+
+ MaxPCIBus = 4;
+ pci_slot_get_irq = astro_pci_slot_get_irq;
+
+ /* setup io address space */
+ pci_io_low_end = IOS_DIST_BASE_SIZE / ROPES_PER_IOC;
+}
+
+static void parisc_mem_addr_setup(struct pci_device *dev, void *arg)
+{
+ if (has_astro)
+ return astro_mem_addr_setup(dev, arg);
+ else
+ return dino_mem_addr_setup(dev, arg);
+}
#endif /* CONFIG_PARISC */
+static unsigned long add_lmmio_directed_range(unsigned long size, int rope)
+{
+#ifdef CONFIG_PARISC
+ int i;
+
+ /* Astro has 4 directed ranges. */
+ for (i = 0; i < 4; i++) {
+ unsigned long addr;
+ void *reg = (void *)(unsigned long) (ASTRO_BASE_HPA + i * 0x18);
+
+ addr = readl(reg + LMMIO_DIRECT0_BASE);
+ if (addr & 1)
+ continue; /* already used */
+
+ /* fixme for multiple addresses */
+ /* Linux driver currently only allows one distr. range per IOC */
+ addr = 0xfa000000; /* graphics card area for parisc, f8 is used by artist */
+ addr += i * 0x02000000;
+
+ writel(reg + LMMIO_DIRECT0_BASE, addr | 1);
+ writel(reg + LMMIO_DIRECT0_ROUTE, rope & (ROPES_PER_IOC - 1));
+ size = 0xfff8000000 | ~(size-1); /* is -1 correct? */
+ // dprintf(1, "use addr %lx size %lx\n", addr|1, size);
+ writel(reg + LMMIO_DIRECT0_MASK, size);
+ return addr;
+ }
+#endif /* CONFIG_PARISC */
+ return -1UL;
+}
static const struct pci_device_id pci_platform_tbl[] = {
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441,
@@ -558,7 +620,7 @@ static void pci_bios_init_platform(void)
}
#if CONFIG_PARISC
- dino_mem_addr_setup(NULL, NULL);
+ parisc_mem_addr_setup(NULL, NULL);
#endif
}
@@ -608,7 +670,7 @@ pci_bios_init_bus_rec(int bus, u8 *pci_bus)
int bdf;
u16 class;
- dprintf(1, "PCI: %s bus = 0x%x\n", __func__, bus);
+ // dprintf(1, "PCI: %s bus = 0x%x\n", __func__, bus);
/* prevent accidental access to unintended devices */
foreachbdf(bdf, bus) {
@@ -785,7 +847,8 @@ static u64 pci_region_sum(struct pci_region *r)
u64 sum = 0;
struct pci_region_entry *entry;
hlist_for_each_entry(entry, &r->list, node) {
- sum += entry->size;
+ if (entry->size <= PARISC_MMIO_LIMIT && CONFIG_PARISC)
+ sum += entry->size;
}
return sum;
}
@@ -900,7 +963,7 @@ static int pci_bios_check_devices(struct pci_bus *busses)
busses[pci->secondary_bus].bus_dev = pci;
struct pci_bus *bus = &busses[pci_bdf_to_bus(pci->bdf)];
- if (!bus->bus_dev)
+ if (!bus->bus_dev && !CONFIG_PARISC)
/*
* Resources for all root busses go in busses[0]
*/
@@ -1095,6 +1158,8 @@ pci_region_map_one_entry(struct pci_region_entry *entry, u64 addr)
u16 bdf = entry->dev->bdf;
u64 limit = addr + entry->size - 1;
+ if (!entry->size)
+ return;
if (entry->type == PCI_REGION_TYPE_IO) {
pci_config_writeb(bdf, PCI_IO_BASE, addr >> PCI_IO_SHIFT);
pci_config_writew(bdf, PCI_IO_BASE_UPPER16, 0);
@@ -1119,7 +1184,13 @@ static void pci_region_map_entries(struct pci_bus *busses, struct pci_region *r)
struct pci_region_entry *entry;
hlist_for_each_entry_safe(entry, n, &r->list, node) {
u64 addr = r->base;
- r->base += entry->size;
+ if (entry->size <= PARISC_MMIO_LIMIT && CONFIG_PARISC)
+ r->base += entry->size;
+ else {
+ addr = add_lmmio_directed_range(entry->size, 0);
+ if (addr == -1UL)
+ hlt();
+ }
if (entry->bar == -1)
// Update bus base address if entry is a bridge region
busses[entry->dev->secondary_bus].r[entry->type].base = addr;