[PATCH 9/14] powerpc: 4xx PLB to PCI-X support

2007-11-20 Thread Benjamin Herrenschmidt
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

2007-11-20 Thread Benjamin Herrenschmidt
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 =