|
@@ -21,6 +21,36 @@ static int dma_offset_set;
|
|
/* Move that to a useable header */
|
|
/* Move that to a useable header */
|
|
extern unsigned long total_memory;
|
|
extern unsigned long total_memory;
|
|
|
|
|
|
|
|
+static void fixup_ppc4xx_pci_bridge(struct pci_dev *dev)
|
|
|
|
+{
|
|
|
|
+ struct pci_controller *hose;
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ if (dev->devfn != 0 || dev->bus->self != NULL)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ hose = pci_bus_to_host(dev->bus);
|
|
|
|
+ if (hose == NULL)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ if (!of_device_is_compatible(hose->dn, "ibm,plb-pciex") &&
|
|
|
|
+ !of_device_is_compatible(hose->dn, "ibm,plb-pcix") &&
|
|
|
|
+ !of_device_is_compatible(hose->dn, "ibm,plb-pci"))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ /* Hide the PCI host BARs from the kernel as their content doesn't
|
|
|
|
+ * fit well in the resource management
|
|
|
|
+ */
|
|
|
|
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
|
|
|
|
+ dev->resource[i].start = dev->resource[i].end = 0;
|
|
|
|
+ dev->resource[i].flags = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ printk(KERN_INFO "PCI: Hiding 4xx host bridge resources %s\n",
|
|
|
|
+ pci_name(dev));
|
|
|
|
+}
|
|
|
|
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, fixup_ppc4xx_pci_bridge);
|
|
|
|
+
|
|
static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
|
|
static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
|
|
void __iomem *reg,
|
|
void __iomem *reg,
|
|
struct resource *res)
|
|
struct resource *res)
|
|
@@ -126,9 +156,157 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
|
|
/*
|
|
/*
|
|
* 4xx PCI 2.x part
|
|
* 4xx PCI 2.x part
|
|
*/
|
|
*/
|
|
|
|
+
|
|
|
|
+static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose,
|
|
|
|
+ void __iomem *reg)
|
|
|
|
+{
|
|
|
|
+ u32 la, ma, pcila, pciha;
|
|
|
|
+ int i, j;
|
|
|
|
+
|
|
|
|
+ /* Setup outbound memory windows */
|
|
|
|
+ for (i = j = 0; i < 3; i++) {
|
|
|
|
+ struct resource *res = &hose->mem_resources[i];
|
|
|
|
+
|
|
|
|
+ /* we only care about memory windows */
|
|
|
|
+ if (!(res->flags & IORESOURCE_MEM))
|
|
|
|
+ continue;
|
|
|
|
+ if (j > 2) {
|
|
|
|
+ printk(KERN_WARNING "%s: Too many ranges\n",
|
|
|
|
+ hose->dn->full_name);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Calculate register values */
|
|
|
|
+ la = res->start;
|
|
|
|
+#ifdef CONFIG_RESOURCES_64BIT
|
|
|
|
+ pciha = (res->start - hose->pci_mem_offset) >> 32;
|
|
|
|
+ pcila = (res->start - hose->pci_mem_offset) & 0xffffffffu;
|
|
|
|
+#else
|
|
|
|
+ pciha = 0;
|
|
|
|
+ pcila = res->start - hose->pci_mem_offset;
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ ma = res->end + 1 - res->start;
|
|
|
|
+ if (!is_power_of_2(ma) || ma < 0x1000 || ma > 0xffffffffu) {
|
|
|
|
+ printk(KERN_WARNING "%s: Resource out of range\n",
|
|
|
|
+ hose->dn->full_name);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ ma = (0xffffffffu << ilog2(ma)) | 0x1;
|
|
|
|
+ if (res->flags & IORESOURCE_PREFETCH)
|
|
|
|
+ ma |= 0x2;
|
|
|
|
+
|
|
|
|
+ /* Program register values */
|
|
|
|
+ writel(la, reg + PCIL0_PMM0LA + (0x10 * j));
|
|
|
|
+ writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * j));
|
|
|
|
+ writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * j));
|
|
|
|
+ writel(ma, reg + PCIL0_PMM0MA + (0x10 * j));
|
|
|
|
+ j++;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void __init ppc4xx_configure_pci_PTMs(struct pci_controller *hose,
|
|
|
|
+ void __iomem *reg,
|
|
|
|
+ const struct resource *res)
|
|
|
|
+{
|
|
|
|
+ resource_size_t size = res->end - res->start + 1;
|
|
|
|
+ u32 sa;
|
|
|
|
+
|
|
|
|
+ /* Calculate window size */
|
|
|
|
+ sa = (0xffffffffu << ilog2(size)) | 1;
|
|
|
|
+ sa |= 0x1;
|
|
|
|
+
|
|
|
|
+ /* RAM is always at 0 local for now */
|
|
|
|
+ writel(0, reg + PCIL0_PTM1LA);
|
|
|
|
+ writel(sa, reg + PCIL0_PTM1MS);
|
|
|
|
+
|
|
|
|
+ /* Map on PCI side */
|
|
|
|
+ early_write_config_dword(hose, hose->first_busno, 0,
|
|
|
|
+ PCI_BASE_ADDRESS_1, res->start);
|
|
|
|
+ early_write_config_dword(hose, hose->first_busno, 0,
|
|
|
|
+ PCI_BASE_ADDRESS_2, 0x00000000);
|
|
|
|
+ early_write_config_word(hose, hose->first_busno, 0,
|
|
|
|
+ PCI_COMMAND, 0x0006);
|
|
|
|
+}
|
|
|
|
+
|
|
static void __init ppc4xx_probe_pci_bridge(struct device_node *np)
|
|
static void __init ppc4xx_probe_pci_bridge(struct device_node *np)
|
|
{
|
|
{
|
|
/* NYI */
|
|
/* NYI */
|
|
|
|
+ struct resource rsrc_cfg;
|
|
|
|
+ struct resource rsrc_reg;
|
|
|
|
+ struct resource dma_window;
|
|
|
|
+ struct pci_controller *hose = NULL;
|
|
|
|
+ void __iomem *reg = NULL;
|
|
|
|
+ const int *bus_range;
|
|
|
|
+ int primary = 0;
|
|
|
|
+
|
|
|
|
+ /* Fetch config space registers address */
|
|
|
|
+ if (of_address_to_resource(np, 0, &rsrc_cfg)) {
|
|
|
|
+ printk(KERN_ERR "%s:Can't get PCI config register base !",
|
|
|
|
+ np->full_name);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ /* Fetch host bridge internal registers address */
|
|
|
|
+ if (of_address_to_resource(np, 3, &rsrc_reg)) {
|
|
|
|
+ printk(KERN_ERR "%s: Can't get PCI internal register base !",
|
|
|
|
+ np->full_name);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Check if primary bridge */
|
|
|
|
+ if (of_get_property(np, "primary", NULL))
|
|
|
|
+ primary = 1;
|
|
|
|
+
|
|
|
|
+ /* Get bus range if any */
|
|
|
|
+ bus_range = of_get_property(np, "bus-range", NULL);
|
|
|
|
+
|
|
|
|
+ /* Map registers */
|
|
|
|
+ reg = ioremap(rsrc_reg.start, rsrc_reg.end + 1 - rsrc_reg.start);
|
|
|
|
+ if (reg == NULL) {
|
|
|
|
+ printk(KERN_ERR "%s: Can't map registers !", np->full_name);
|
|
|
|
+ goto fail;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Allocate the host controller data structure */
|
|
|
|
+ hose = pcibios_alloc_controller(np);
|
|
|
|
+ if (!hose)
|
|
|
|
+ goto fail;
|
|
|
|
+
|
|
|
|
+ hose->first_busno = bus_range ? bus_range[0] : 0x0;
|
|
|
|
+ hose->last_busno = bus_range ? bus_range[1] : 0xff;
|
|
|
|
+
|
|
|
|
+ /* Setup config space */
|
|
|
|
+ setup_indirect_pci(hose, rsrc_cfg.start, rsrc_cfg.start + 0x4, 0);
|
|
|
|
+
|
|
|
|
+ /* Disable all windows */
|
|
|
|
+ writel(0, reg + PCIL0_PMM0MA);
|
|
|
|
+ writel(0, reg + PCIL0_PMM1MA);
|
|
|
|
+ writel(0, reg + PCIL0_PMM2MA);
|
|
|
|
+ writel(0, reg + PCIL0_PTM1MS);
|
|
|
|
+ writel(0, reg + PCIL0_PTM2MS);
|
|
|
|
+
|
|
|
|
+ /* Parse outbound mapping resources */
|
|
|
|
+ pci_process_bridge_OF_ranges(hose, np, primary);
|
|
|
|
+
|
|
|
|
+ /* Parse inbound mapping resources */
|
|
|
|
+ if (ppc4xx_parse_dma_ranges(hose, reg, &dma_window) != 0)
|
|
|
|
+ goto fail;
|
|
|
|
+
|
|
|
|
+ /* Configure outbound ranges POMs */
|
|
|
|
+ ppc4xx_configure_pci_PMMs(hose, reg);
|
|
|
|
+
|
|
|
|
+ /* Configure inbound ranges PIMs */
|
|
|
|
+ ppc4xx_configure_pci_PTMs(hose, reg, &dma_window);
|
|
|
|
+
|
|
|
|
+ /* We don't need the registers anymore */
|
|
|
|
+ iounmap(reg);
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ fail:
|
|
|
|
+ if (hose)
|
|
|
|
+ pcibios_free_controller(hose);
|
|
|
|
+ if (reg)
|
|
|
|
+ iounmap(reg);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -155,7 +333,7 @@ static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose,
|
|
}
|
|
}
|
|
|
|
|
|
/* Calculate register values */
|
|
/* Calculate register values */
|
|
-#ifdef CONFIG_PTE_64BIT
|
|
|
|
|
|
+#ifdef CONFIG_RESOURCES_64BIT
|
|
lah = res->start >> 32;
|
|
lah = res->start >> 32;
|
|
lal = res->start & 0xffffffffu;
|
|
lal = res->start & 0xffffffffu;
|
|
pciah = (res->start - hose->pci_mem_offset) >> 32;
|
|
pciah = (res->start - hose->pci_mem_offset) >> 32;
|