static int __init ppc4xx_setup_one_pciex_POM(struct ppc4xx_pciex_port *port, struct pci_controller *hose, void __iomem *mbase, u64 plb_addr, u64 pci_addr, u64 size, unsigned int flags, int index) { u32 lah, lal, pciah, pcial, sa; if (!is_power_of_2(size) || (index < 2 && size < 0x100000) || (index == 2 && size < 0x100) || (plb_addr & (size - 1)) != 0) { printk(KERN_WARNING "%s: Resource out of range\n", hose->dn->full_name); return -1; } /* Calculate register values */ lah = RES_TO_U32_HIGH(plb_addr); lal = RES_TO_U32_LOW(plb_addr); pciah = RES_TO_U32_HIGH(pci_addr); pcial = RES_TO_U32_LOW(pci_addr); sa = (0xffffffffu << ilog2(size)) | 0x1; /* Program register values */ switch (index) { case 0: out_le32(mbase + PECFG_POM0LAH, pciah); out_le32(mbase + PECFG_POM0LAL, pcial); dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah); dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal); dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff); /* Note that 3 here means enabled | single region */ dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3); break; case 1: out_le32(mbase + PECFG_POM1LAH, pciah); out_le32(mbase + PECFG_POM1LAL, pcial); dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah); dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal); dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff); /* Note that 3 here means enabled | single region */ dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3); break; case 2: out_le32(mbase + PECFG_POM2LAH, pciah); out_le32(mbase + PECFG_POM2LAL, pcial); dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah); dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal); dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff); /* Note that 3 here means enabled | IO space !!! */ dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, sa | 3); break; } return 0; }
static void __init ppc4xx_pciex_port_init_mapping(struct ppc4xx_pciex_port *port) { /* We map PCI Express configuration based on the reg property */ dcr_write(port->dcrs, DCRO_PEGPL_CFGBAH, RES_TO_U32_HIGH(port->cfg_space.start)); dcr_write(port->dcrs, DCRO_PEGPL_CFGBAL, RES_TO_U32_LOW(port->cfg_space.start)); /* XXX FIXME: Use size from reg property. For now, map 512M */ dcr_write(port->dcrs, DCRO_PEGPL_CFGMSK, 0xe0000001); /* We map UTL registers based on the reg property */ dcr_write(port->dcrs, DCRO_PEGPL_REGBAH, RES_TO_U32_HIGH(port->utl_regs.start)); dcr_write(port->dcrs, DCRO_PEGPL_REGBAL, RES_TO_U32_LOW(port->utl_regs.start)); /* XXX FIXME: Use size from reg property */ dcr_write(port->dcrs, DCRO_PEGPL_REGMSK, 0x00007001); /* Disable all other outbound windows */ dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, 0); dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, 0); dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, 0); dcr_write(port->dcrs, DCRO_PEGPL_MSGMSK, 0); }
static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, void __iomem *reg) { u32 lah, lal, pciah, pcial, sa; 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 > 1) { printk(KERN_WARNING "%s: Too many ranges\n", hose->dn->full_name); break; } /* Calculate register values */ lah = RES_TO_U32_HIGH(res->start); lal = RES_TO_U32_LOW(res->start); pciah = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); pcial = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); sa = res->end + 1 - res->start; if (!is_power_of_2(sa) || sa < 0x100000 || sa > 0xffffffffu) { printk(KERN_WARNING "%s: Resource out of range\n", hose->dn->full_name); continue; } sa = (0xffffffffu << ilog2(sa)) | 0x1; /* Program register values */ if (j == 0) { writel(lah, reg + PCIX0_POM0LAH); writel(lal, reg + PCIX0_POM0LAL); writel(pciah, reg + PCIX0_POM0PCIAH); writel(pcial, reg + PCIX0_POM0PCIAL); writel(sa, reg + PCIX0_POM0SA); } else { writel(lah, reg + PCIX0_POM1LAH); writel(lal, reg + PCIX0_POM1LAL); writel(pciah, reg + PCIX0_POM1PCIAH); writel(pcial, reg + PCIX0_POM1PCIAL); writel(sa, reg + PCIX0_POM1SA); } j++; } }
static int __init ppc4xx_setup_one_pcix_POM(struct pci_controller *hose, void __iomem *reg, u64 plb_addr, u64 pci_addr, u64 size, unsigned int flags, int index) { u32 lah, lal, pciah, pcial, sa; if (!is_power_of_2(size) || size < 0x1000 || (plb_addr & (size - 1)) != 0) { printk(KERN_WARNING "%s: Resource out of range\n", hose->dn->full_name); return -1; } /* Calculate register values */ lah = RES_TO_U32_HIGH(plb_addr); lal = RES_TO_U32_LOW(plb_addr); pciah = RES_TO_U32_HIGH(pci_addr); pcial = RES_TO_U32_LOW(pci_addr); sa = (0xffffffffu << ilog2(size)) | 0x1; /* Program register values */ if (index == 0) { writel(lah, reg + PCIX0_POM0LAH); writel(lal, reg + PCIX0_POM0LAL); writel(pciah, reg + PCIX0_POM0PCIAH); writel(pcial, reg + PCIX0_POM0PCIAL); writel(sa, reg + PCIX0_POM0SA); } else { writel(lah, reg + PCIX0_POM1LAH); writel(lal, reg + PCIX0_POM1LAL); writel(pciah, reg + PCIX0_POM1PCIAH); writel(pcial, reg + PCIX0_POM1PCIAL); writel(sa, reg + PCIX0_POM1SA); } return 0; }
static int __init ppc4xx_setup_one_pci_PMM(struct pci_controller *hose, void __iomem *reg, u64 plb_addr, u64 pci_addr, u64 size, unsigned int flags, int index) { u32 ma, pcila, pciha; /* Hack warning ! The "old" PCI 2.x cell only let us configure the low * 32-bit of incoming PLB addresses. The top 4 bits of the 36-bit * address are actually hard wired to a value that appears to depend * on the specific SoC. For example, it's 0 on 440EP and 1 on 440EPx. * * The trick here is we just crop those top bits and ignore them when * programming the chip. That means the device-tree has to be right * for the specific part used (we don't print a warning if it's wrong * but on the other hand, you'll crash quickly enough), but at least * this code should work whatever the hard coded value is */ plb_addr &= 0xffffffffull; /* Note: Due to the above hack, the test below doesn't actually test * if you address is above 4G, but it tests that address and * (address + size) are both contained in the same 4G */ if ((plb_addr + size) > 0xffffffffull || !is_power_of_2(size) || size < 0x1000 || (plb_addr & (size - 1)) != 0) { printk(KERN_WARNING "%s: Resource out of range\n", hose->dn->full_name); return -1; } ma = (0xffffffffu << ilog2(size)) | 1; if (flags & IORESOURCE_PREFETCH) ma |= 2; pciha = RES_TO_U32_HIGH(pci_addr); pcila = RES_TO_U32_LOW(pci_addr); writel(plb_addr, reg + PCIL0_PMM0LA + (0x10 * index)); writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * index)); writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * index)); writel(ma, reg + PCIL0_PMM0MA + (0x10 * index)); return 0; }
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; pciha = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); pcila = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); 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_pciex_PIMs(struct ppc4xx_pciex_port *port, struct pci_controller *hose, void __iomem *mbase, struct resource *res) { resource_size_t size = res->end - res->start + 1; u64 sa; if (port->endpoint) { resource_size_t ep_addr = 0; resource_size_t ep_size = 32 << 20; /* Currently we map a fixed 64MByte window to PLB address * 0 (SDRAM). This should probably be configurable via a dts * property. */ /* Calculate window size */ sa = (0xffffffffffffffffull << ilog2(ep_size)); /* Setup BAR0 */ out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa)); out_le32(mbase + PECFG_BAR0LMPA, RES_TO_U32_LOW(sa) | PCI_BASE_ADDRESS_MEM_TYPE_64); /* Disable BAR1 & BAR2 */ out_le32(mbase + PECFG_BAR1MPA, 0); out_le32(mbase + PECFG_BAR2HMPA, 0); out_le32(mbase + PECFG_BAR2LMPA, 0); out_le32(mbase + PECFG_PIM01SAH, RES_TO_U32_HIGH(sa)); out_le32(mbase + PECFG_PIM01SAL, RES_TO_U32_LOW(sa)); out_le32(mbase + PCI_BASE_ADDRESS_0, RES_TO_U32_LOW(ep_addr)); out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(ep_addr)); } else { /* Calculate window size */ sa = (0xffffffffffffffffull << ilog2(size)); if (res->flags & IORESOURCE_PREFETCH) sa |= 0x8; out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa)); out_le32(mbase + PECFG_BAR0LMPA, RES_TO_U32_LOW(sa)); /* The setup of the split looks weird to me ... let's see * if it works */ out_le32(mbase + PECFG_PIM0LAL, 0x00000000); out_le32(mbase + PECFG_PIM0LAH, 0x00000000); out_le32(mbase + PECFG_PIM1LAL, 0x00000000); out_le32(mbase + PECFG_PIM1LAH, 0x00000000); out_le32(mbase + PECFG_PIM01SAH, 0xffff0000); out_le32(mbase + PECFG_PIM01SAL, 0x00000000); out_le32(mbase + PCI_BASE_ADDRESS_0, RES_TO_U32_LOW(res->start)); out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(res->start)); } /* Enable inbound mapping */ out_le32(mbase + PECFG_PIMEN, 0x1); /* Enable I/O, Mem, and Busmaster cycles */ out_le16(mbase + PCI_COMMAND, in_le16(mbase + PCI_COMMAND) | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); }
static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port, struct pci_controller *hose, void __iomem *mbase) { u32 lah, lal, pciah, pcial, sa; 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 > 1) { printk(KERN_WARNING "%s: Too many ranges\n", port->node->full_name); break; } /* Calculate register values */ lah = RES_TO_U32_HIGH(res->start); lal = RES_TO_U32_LOW(res->start); pciah = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); pcial = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); sa = res->end + 1 - res->start; if (!is_power_of_2(sa) || sa < 0x100000 || sa > 0xffffffffu) { printk(KERN_WARNING "%s: Resource out of range\n", port->node->full_name); continue; } sa = (0xffffffffu << ilog2(sa)) | 0x1; /* Program register values */ switch (j) { case 0: out_le32(mbase + PECFG_POM0LAH, pciah); out_le32(mbase + PECFG_POM0LAL, pcial); dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah); dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal); dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff); dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3); break; case 1: out_le32(mbase + PECFG_POM1LAH, pciah); out_le32(mbase + PECFG_POM1LAL, pcial); dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah); dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal); dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff); dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3); break; } j++; } /* Configure IO, always 64K starting at 0 */ if (hose->io_resource.flags & IORESOURCE_IO) { lah = RES_TO_U32_HIGH(hose->io_base_phys); lal = RES_TO_U32_LOW(hose->io_base_phys); out_le32(mbase + PECFG_POM2LAH, 0); out_le32(mbase + PECFG_POM2LAL, 0); dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah); dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal); dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff); dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, 0xffff0000 | 3); } }