[PATCH 9/14] powerpc: 4xx PLB to PCI-X support
This adds base support code for the 4xx PCI-X bridge. It also provides placeholders for the PCI and PCI-E version but they aren't supported with this patch. The bridges are configured based on device-tree properties. Signed-off-by: Benjamin Herrenschmidt [EMAIL PROTECTED] --- Tested on 440GP only so far. arch/powerpc/sysdev/Makefile |4 arch/powerpc/sysdev/ppc4xx_pci.c | 313 +++ arch/powerpc/sysdev/ppc4xx_pci.h | 106 + include/asm-powerpc/pci-bridge.h |3 4 files changed, 426 insertions(+) Index: linux-work/arch/powerpc/sysdev/Makefile === --- linux-work.orig/arch/powerpc/sysdev/Makefile2007-11-20 17:04:07.0 +1100 +++ linux-work/arch/powerpc/sysdev/Makefile 2007-11-20 17:04:52.0 +1100 @@ -29,6 +29,10 @@ obj-$(CONFIG_4xx)+= uic.o obj-$(CONFIG_XILINX_VIRTEX)+= xilinx_intc.o endif +ifeq ($(CONFIG_PCI),y) +obj-$(CONFIG_4xx) += ppc4xx_pci.o +endif + # Temporary hack until we have migrated to asm-powerpc ifeq ($(ARCH),powerpc) obj-$(CONFIG_CPM) += cpm_common.o Index: linux-work/arch/powerpc/sysdev/ppc4xx_pci.c === --- /dev/null 1970-01-01 00:00:00.0 + +++ linux-work/arch/powerpc/sysdev/ppc4xx_pci.c 2007-11-21 11:41:58.0 +1100 @@ -0,0 +1,313 @@ +/* + * PCI / PCI-X / PCI-Express support for 4xx parts + * + * Copyright 2007 Ben. Herrenschmidt [EMAIL PROTECTED], IBM Corp. + * + */ + +#include linux/kernel.h +#include linux/pci.h +#include linux/init.h +#include linux/bootmem.h +#include linux/of.h + +#include asm/io.h +#include asm/pci-bridge.h +#include asm/machdep.h + +#include ppc4xx_pci.h + +static int dma_offset_set; + +/* Move that to a useable header */ +extern unsigned long total_memory; + +/* Defined in drivers/pci/pci.c but not exposed by a header */ +extern u8 pci_cache_line_size; + +static int __init ppc4xx_parse_dma_window(struct pci_controller *hose, + void __iomem *reg, + struct resource *res) +{ + struct device_node *np = hose-arch_data; + u64 size; + const u32 *dmaw; + + /* Default */ + res-start = 0; + res-end = 0x8000; + res-flags = IORESOURCE_MEM | IORESOURCE_PREFETCH; + + /* Get dma-window property */ + dmaw = of_get_property(np, dma-window, NULL); + if (dmaw == NULL) + goto out; + + /* Check if it makes sense (ie. it encodes memory */ + if ((dmaw[0] 0x0300) != 0x0200) { + printk(KERN_ERR %s: non-memory dma-window\n, + np-full_name); + return -ENXIO; + } + + /* Check if not prefetchable */ + if (!(dmaw[0] 0x4000)) + res-flags = ~IORESOURCE_PREFETCH; + + /* Read the DMA window. We should sanity check that it's +* not overlapping with the outbound ranges. +*/ + res-start = of_read_number(dmaw + 1, 2); + size = of_read_number(dmaw + 3, 2); + res-end = res-start + size - 1; + + /* We only support one global DMA offset */ + if (dma_offset_set pci_dram_offset != res-start) { + printk(KERN_ERR %s: dma-window(s) mismatch\n, + np-full_name); + return -ENXIO; + } + + /* Check that we can fit all of memory as we don't support +* DMA bounce buffers +*/ + if (size total_memory) { + printk(KERN_ERR %s: dma-window too small\n, + np-full_name); + return -ENXIO; + } + + /* Check we are a power of 2 size and that base is a multiple of size*/ + if (!is_power_of_2(size) || + (res-start (size - 1)) != 0) { + printk(KERN_ERR %s: dma-window unaligned\n, + np-full_name); + return -ENXIO; + } + + /* Check that we are fully contained within 32 bits space */ + if (res-end 0x) { + printk(KERN_ERR %s: dma-window outside of 32 bits space\n, + np-full_name); + return -ENXIO; + } + out: + dma_offset_set = 1; + pci_dram_offset = res-start; + + printk(KERN_INFO 4xx PCI DMA offset set to 0x%08lx\n, + pci_dram_offset); + return 0; +} + +/* + * 4xx PCI 2.x part + */ +static void __init ppc4xx_probe_pci_bridge(struct device_node *np) +{ + /* NYI */ +} + +/* + * 4xx PCI-X part + */ + +static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, + void __iomem *reg) +{ + struct device_node *np = hose-arch_data; + u32 lah, lal, pciah, pcial, sa; + int i, j; + + /* Setup outbound memory windows */ + for(i = j =
[RFC/PATCH 9/14] powerpc: 4xx PLB to PCI-X support
This adds base support code for the 4xx PCI-X bridge. It also provides placeholders for the PCI and PCI-E version but they aren't supported with this patch. The bridges are configured based on device-tree properties. Signed-off-by: Benjamin Herrenschmidt [EMAIL PROTECTED] --- Tested on 440GP only so far. arch/powerpc/sysdev/Makefile |4 arch/powerpc/sysdev/ppc4xx_pci.c | 313 +++ arch/powerpc/sysdev/ppc4xx_pci.h | 106 + include/asm-powerpc/pci-bridge.h |3 4 files changed, 426 insertions(+) Index: linux-work/arch/powerpc/sysdev/Makefile === --- linux-work.orig/arch/powerpc/sysdev/Makefile2007-11-20 17:04:07.0 +1100 +++ linux-work/arch/powerpc/sysdev/Makefile 2007-11-20 17:04:52.0 +1100 @@ -29,6 +29,10 @@ obj-$(CONFIG_4xx)+= uic.o obj-$(CONFIG_XILINX_VIRTEX)+= xilinx_intc.o endif +ifeq ($(CONFIG_PCI),y) +obj-$(CONFIG_4xx) += ppc4xx_pci.o +endif + # Temporary hack until we have migrated to asm-powerpc ifeq ($(ARCH),powerpc) obj-$(CONFIG_CPM) += cpm_common.o Index: linux-work/arch/powerpc/sysdev/ppc4xx_pci.c === --- /dev/null 1970-01-01 00:00:00.0 + +++ linux-work/arch/powerpc/sysdev/ppc4xx_pci.c 2007-11-21 11:41:58.0 +1100 @@ -0,0 +1,313 @@ +/* + * PCI / PCI-X / PCI-Express support for 4xx parts + * + * Copyright 2007 Ben. Herrenschmidt [EMAIL PROTECTED], IBM Corp. + * + */ + +#include linux/kernel.h +#include linux/pci.h +#include linux/init.h +#include linux/bootmem.h +#include linux/of.h + +#include asm/io.h +#include asm/pci-bridge.h +#include asm/machdep.h + +#include ppc4xx_pci.h + +static int dma_offset_set; + +/* Move that to a useable header */ +extern unsigned long total_memory; + +/* Defined in drivers/pci/pci.c but not exposed by a header */ +extern u8 pci_cache_line_size; + +static int __init ppc4xx_parse_dma_window(struct pci_controller *hose, + void __iomem *reg, + struct resource *res) +{ + struct device_node *np = hose-arch_data; + u64 size; + const u32 *dmaw; + + /* Default */ + res-start = 0; + res-end = 0x8000; + res-flags = IORESOURCE_MEM | IORESOURCE_PREFETCH; + + /* Get dma-window property */ + dmaw = of_get_property(np, dma-window, NULL); + if (dmaw == NULL) + goto out; + + /* Check if it makes sense (ie. it encodes memory */ + if ((dmaw[0] 0x0300) != 0x0200) { + printk(KERN_ERR %s: non-memory dma-window\n, + np-full_name); + return -ENXIO; + } + + /* Check if not prefetchable */ + if (!(dmaw[0] 0x4000)) + res-flags = ~IORESOURCE_PREFETCH; + + /* Read the DMA window. We should sanity check that it's +* not overlapping with the outbound ranges. +*/ + res-start = of_read_number(dmaw + 1, 2); + size = of_read_number(dmaw + 3, 2); + res-end = res-start + size - 1; + + /* We only support one global DMA offset */ + if (dma_offset_set pci_dram_offset != res-start) { + printk(KERN_ERR %s: dma-window(s) mismatch\n, + np-full_name); + return -ENXIO; + } + + /* Check that we can fit all of memory as we don't support +* DMA bounce buffers +*/ + if (size total_memory) { + printk(KERN_ERR %s: dma-window too small\n, + np-full_name); + return -ENXIO; + } + + /* Check we are a power of 2 size and that base is a multiple of size*/ + if (!is_power_of_2(size) || + (res-start (size - 1)) != 0) { + printk(KERN_ERR %s: dma-window unaligned\n, + np-full_name); + return -ENXIO; + } + + /* Check that we are fully contained within 32 bits space */ + if (res-end 0x) { + printk(KERN_ERR %s: dma-window outside of 32 bits space\n, + np-full_name); + return -ENXIO; + } + out: + dma_offset_set = 1; + pci_dram_offset = res-start; + + printk(KERN_INFO 4xx PCI DMA offset set to 0x%08lx\n, + pci_dram_offset); + return 0; +} + +/* + * 4xx PCI 2.x part + */ +static void __init ppc4xx_probe_pci_bridge(struct device_node *np) +{ + /* NYI */ +} + +/* + * 4xx PCI-X part + */ + +static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, + void __iomem *reg) +{ + struct device_node *np = hose-arch_data; + u32 lah, lal, pciah, pcial, sa; + int i, j; + + /* Setup outbound memory windows */ + for(i = j =