diff options
Diffstat (limited to 'arch/powerpc/sysdev/ppc4xx_pci.c')
-rw-r--r-- | arch/powerpc/sysdev/ppc4xx_pci.c | 354 |
1 files changed, 233 insertions, 121 deletions
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index fb368dfde5d..77fae5f64f2 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c @@ -30,24 +30,19 @@ #include <asm/machdep.h> #include <asm/dcr.h> #include <asm/dcr-regs.h> +#include <mm/mmu_decl.h> #include "ppc4xx_pci.h" static int dma_offset_set; -/* Move that to a useable header */ -extern unsigned long total_memory; - #define U64_TO_U32_LOW(val) ((u32)((val) & 0x00000000ffffffffULL)) #define U64_TO_U32_HIGH(val) ((u32)((val) >> 32)) -#ifdef CONFIG_RESOURCES_64BIT -#define RES_TO_U32_LOW(val) U64_TO_U32_LOW(val) -#define RES_TO_U32_HIGH(val) U64_TO_U32_HIGH(val) -#else -#define RES_TO_U32_LOW(val) (val) -#define RES_TO_U32_HIGH(val) (0) -#endif +#define RES_TO_U32_LOW(val) \ + ((sizeof(resource_size_t) > sizeof(u32)) ? U64_TO_U32_LOW(val) : (val)) +#define RES_TO_U32_HIGH(val) \ + ((sizeof(resource_size_t) > sizeof(u32)) ? U64_TO_U32_HIGH(val) : (0)) static inline int ppc440spe_revA(void) { @@ -105,7 +100,8 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, /* Default */ res->start = 0; - res->end = size = 0x80000000; + size = 0x80000000; + res->end = size - 1; res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH; /* Get dma-ranges property */ @@ -145,12 +141,11 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, /* Use that */ res->start = pci_addr; -#ifndef CONFIG_RESOURCES_64BIT /* Beware of 32 bits resources */ - if ((pci_addr + size) > 0x100000000ull) + if (sizeof(resource_size_t) == sizeof(u32) && + (pci_addr + size) > 0x100000000ull) res->end = 0xffffffff; else -#endif res->end = res->start + size - 1; break; } @@ -167,13 +162,13 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, */ if (size < total_memory) { printk(KERN_ERR "%s: dma-ranges too small " - "(size=%llx total_memory=%lx)\n", - hose->dn->full_name, size, total_memory); + "(size=%llx total_memory=%llx)\n", + hose->dn->full_name, size, (u64)total_memory); return -ENXIO; } /* Check we are a power of 2 size and that base is a multiple of size*/ - if (!is_power_of_2(size) || + if ((size & (size - 1)) != 0 || (res->start & (size - 1)) != 0) { printk(KERN_ERR "%s: dma-ranges unaligned\n", hose->dn->full_name); @@ -199,11 +194,41 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, * 4xx PCI 2.x part */ +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; + + 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; + int i, j, found_isa_hole = 0; /* Setup outbound memory windows */ for (i = j = 0; i < 3; i++) { @@ -218,28 +243,29 @@ static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose, 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; + /* Configure the resource */ + if (ppc4xx_setup_one_pci_PMM(hose, reg, + res->start, + res->start - hose->pci_mem_offset, + res->end + 1 - res->start, + res->flags, + j) == 0) { + j++; + + /* If the resource PCI address is 0 then we have our + * ISA memory hole + */ + if (res->start == hose->pci_mem_offset) + found_isa_hole = 1; } - 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++; } + + /* Handle ISA memory hole if not already covered */ + if (j <= 2 && !found_isa_hole && hose->isa_mem_size) + if (ppc4xx_setup_one_pci_PMM(hose, reg, hose->isa_mem_phys, 0, + hose->isa_mem_size, 0, j) == 0) + printk(KERN_INFO "%s: Legacy ISA memory support enabled\n", + hose->dn->full_name); } static void __init ppc4xx_configure_pci_PTMs(struct pci_controller *hose, @@ -277,9 +303,16 @@ static void __init ppc4xx_probe_pci_bridge(struct device_node *np) const int *bus_range; int primary = 0; + /* Check if device is enabled */ + if (!of_device_is_available(np)) { + printk(KERN_INFO "%s: Port disabled via device-tree\n", + np->full_name); + return; + } + /* 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 !", + printk(KERN_ERR "%s: Can't get PCI config register base !", np->full_name); return; } @@ -350,11 +383,52 @@ static void __init ppc4xx_probe_pci_bridge(struct device_node *np) * 4xx PCI-X part */ +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 void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, void __iomem *reg) { - u32 lah, lal, pciah, pcial, sa; - int i, j; + int i, j, found_isa_hole = 0; /* Setup outbound memory windows */ for (i = j = 0; i < 3; i++) { @@ -369,36 +443,29 @@ static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, 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); + /* Configure the resource */ + if (ppc4xx_setup_one_pcix_POM(hose, reg, + res->start, + res->start - hose->pci_mem_offset, + res->end + 1 - res->start, + res->flags, + j) == 0) { + j++; + + /* If the resource PCI address is 0 then we have our + * ISA memory hole + */ + if (res->start == hose->pci_mem_offset) + found_isa_hole = 1; } - j++; } + + /* Handle ISA memory hole if not already covered */ + if (j <= 1 && !found_isa_hole && hose->isa_mem_size) + if (ppc4xx_setup_one_pcix_POM(hose, reg, hose->isa_mem_phys, 0, + hose->isa_mem_size, 0, j) == 0) + printk(KERN_INFO "%s: Legacy ISA memory support enabled\n", + hose->dn->full_name); } static void __init ppc4xx_configure_pcix_PIMs(struct pci_controller *hose, @@ -810,7 +877,7 @@ static int ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) switch (port->index) { case 0: mtdcri(SDR0, PESDR0_460EX_L0CDRCTL, 0x00003230); - mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000136); + mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000130); mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006); mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST,0x10000000); @@ -821,10 +888,10 @@ static int ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) mtdcri(SDR0, PESDR1_460EX_L1CDRCTL, 0x00003230); mtdcri(SDR0, PESDR1_460EX_L2CDRCTL, 0x00003230); mtdcri(SDR0, PESDR1_460EX_L3CDRCTL, 0x00003230); - mtdcri(SDR0, PESDR1_460EX_L0DRV, 0x00000136); - mtdcri(SDR0, PESDR1_460EX_L1DRV, 0x00000136); - mtdcri(SDR0, PESDR1_460EX_L2DRV, 0x00000136); - mtdcri(SDR0, PESDR1_460EX_L3DRV, 0x00000136); + mtdcri(SDR0, PESDR1_460EX_L0DRV, 0x00000130); + mtdcri(SDR0, PESDR1_460EX_L1DRV, 0x00000130); + mtdcri(SDR0, PESDR1_460EX_L2DRV, 0x00000130); + mtdcri(SDR0, PESDR1_460EX_L3DRV, 0x00000130); mtdcri(SDR0, PESDR1_460EX_L0CLK, 0x00000006); mtdcri(SDR0, PESDR1_460EX_L1CLK, 0x00000006); mtdcri(SDR0, PESDR1_460EX_L2CLK, 0x00000006); @@ -1315,12 +1382,72 @@ static struct pci_ops ppc4xx_pciex_pci_ops = .write = ppc4xx_pciex_write_config, }; +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_configure_pciex_POMs(struct ppc4xx_pciex_port *port, struct pci_controller *hose, void __iomem *mbase) { - u32 lah, lal, pciah, pcial, sa; - int i, j; + int i, j, found_isa_hole = 0; /* Setup outbound memory windows */ for (i = j = 0; i < 3; i++) { @@ -1335,53 +1462,38 @@ static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port, 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; + /* Configure the resource */ + if (ppc4xx_setup_one_pciex_POM(port, hose, mbase, + res->start, + res->start - hose->pci_mem_offset, + res->end + 1 - res->start, + res->flags, + j) == 0) { + j++; + + /* If the resource PCI address is 0 then we have our + * ISA memory hole + */ + if (res->start == hose->pci_mem_offset) + found_isa_hole = 1; } - 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); - } + /* Handle ISA memory hole if not already covered */ + if (j <= 1 && !found_isa_hole && hose->isa_mem_size) + if (ppc4xx_setup_one_pciex_POM(port, hose, mbase, + hose->isa_mem_phys, 0, + hose->isa_mem_size, 0, j) == 0) + printk(KERN_INFO "%s: Legacy ISA memory support enabled\n", + hose->dn->full_name); + + /* Configure IO, always 64K starting at 0. We hard wire it to 64K ! + * Note also that it -has- to be region index 2 on this HW + */ + if (hose->io_resource.flags & IORESOURCE_IO) + ppc4xx_setup_one_pciex_POM(port, hose, mbase, + hose->io_base_phys, 0, + 0x10000, IORESOURCE_IO, 2); } static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, |