aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc/sysdev/ppc4xx_pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/sysdev/ppc4xx_pci.c')
-rw-r--r--arch/powerpc/sysdev/ppc4xx_pci.c354
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,