]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
microblaze: Add support for Xilinx PCI host bridge
authorMichal Simek <monstr@monstr.eu>
Mon, 18 Jan 2010 14:27:11 +0000 (15:27 +0100)
committerMichal Simek <monstr@monstr.eu>
Thu, 11 Mar 2010 13:05:18 +0000 (14:05 +0100)
This patch is based on powerpc patch
64f16502475ddf663169369fffff6da9b10ea9fb

We did some cleanups and removed powerpc parts.
There is one new debug early listing function too.

Exclude function is only in Debug options.

We tested in on custom board.

Signed-off-by: Michal Simek <monstr@monstr.eu>
arch/microblaze/Kconfig
arch/microblaze/include/asm/pci.h
arch/microblaze/kernel/setup.c
arch/microblaze/pci/Makefile
arch/microblaze/pci/xilinx_pci.c [new file with mode: 0644]

index e1fa0844ba4e1165c58ff2db669def5949fe3db9..c1e731bb3301bcdba5083fcae05aa351977f3bcd 100644 (file)
@@ -267,6 +267,10 @@ config PCI_DOMAINS
 config PCI_SYSCALL
        def_bool PCI
 
+config PCI_XILINX
+       bool "Xilinx PCI host bridge support"
+       depends on PCI
+
 source "drivers/pci/Kconfig"
 
 endmenu
index fecc04481101999b79585b3683e95464e958fdea..bdd65aaee30d3d79d658fc3131382f71b3688854 100644 (file)
@@ -166,5 +166,12 @@ extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
 extern void pcibios_setup_bus_devices(struct pci_bus *bus);
 extern void pcibios_setup_bus_self(struct pci_bus *bus);
 
+/* This part of code was originaly in xilinx-pci.h */
+#ifdef CONFIG_PCI_XILINX
+extern void __init xilinx_pci_init(void);
+#else
+static inline void __init xilinx_pci_init(void) { return; }
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* __ASM_MICROBLAZE_PCI_H */
index bc325ac4efd3751c108017c6790c8c21ca85305c..cd68e988b48ce99c036d7409d49dac08dc5c5b78 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/io.h>
 #include <linux/bug.h>
 #include <linux/param.h>
+#include <linux/pci.h>
 #include <linux/cache.h>
 #include <linux/of_platform.h>
 #include <linux/dma-mapping.h>
@@ -64,6 +65,8 @@ void __init setup_arch(char **cmdline_p)
 
        setup_memory();
 
+       xilinx_pci_init();
+
 #if defined(CONFIG_SELFMOD_INTC) || defined(CONFIG_SELFMOD_TIMER)
        printk(KERN_NOTICE "Self modified code enable\n");
 #endif
index 2b8901864b23e61e4577a110805608835301363a..9889cc2e129452d4236a08372d473c6d302664cd 100644 (file)
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_PCI)              += pci_32.o pci-common.o indirect_pci.o iomap.o
+obj-$(CONFIG_PCI_XILINX)       += xilinx_pci.o
diff --git a/arch/microblaze/pci/xilinx_pci.c b/arch/microblaze/pci/xilinx_pci.c
new file mode 100644 (file)
index 0000000..7869a41
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * PCI support for Xilinx plbv46_pci soft-core which can be used on
+ * Xilinx Virtex ML410 / ML510 boards.
+ *
+ * Copyright 2009 Roderick Colenbrander
+ * Copyright 2009 Secret Lab Technologies Ltd.
+ *
+ * The pci bridge fixup code was copied from ppc4xx_pci.c and was written
+ * by Benjamin Herrenschmidt.
+ * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/ioport.h>
+#include <linux/of.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#define XPLB_PCI_ADDR 0x10c
+#define XPLB_PCI_DATA 0x110
+#define XPLB_PCI_BUS  0x114
+
+#define PCI_HOST_ENABLE_CMD (PCI_COMMAND_SERR | PCI_COMMAND_PARITY | \
+                               PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY)
+
+static struct of_device_id xilinx_pci_match[] = {
+       { .compatible = "xlnx,plbv46-pci-1.03.a", },
+       {}
+};
+
+/**
+ * xilinx_pci_fixup_bridge - Block Xilinx PHB configuration.
+ */
+static void xilinx_pci_fixup_bridge(struct pci_dev *dev)
+{
+       struct pci_controller *hose;
+       int i;
+
+       if (dev->devfn || dev->bus->self)
+               return;
+
+       hose = pci_bus_to_host(dev->bus);
+       if (!hose)
+               return;
+
+       if (!of_match_node(xilinx_pci_match, hose->dn))
+               return;
+
+       /* Hide the PCI host BARs from the kernel as their content doesn't
+        * fit well in the resource management
+        */
+       for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+               dev->resource[i].start = 0;
+               dev->resource[i].end = 0;
+               dev->resource[i].flags = 0;
+       }
+
+       dev_info(&dev->dev, "Hiding Xilinx plb-pci host bridge resources %s\n",
+                pci_name(dev));
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, xilinx_pci_fixup_bridge);
+
+#ifdef DEBUG
+/**
+ * xilinx_pci_exclude_device - Don't do config access for non-root bus
+ *
+ * This is a hack.  Config access to any bus other than bus 0 does not
+ * currently work on the ML510 so we prevent it here.
+ */
+static int
+xilinx_pci_exclude_device(struct pci_controller *hose, u_char bus, u8 devfn)
+{
+       return (bus != 0);
+}
+
+/**
+ * xilinx_early_pci_scan - List pci config space for available devices
+ *
+ * List pci devices in very early phase.
+ */
+void __init xilinx_early_pci_scan(struct pci_controller *hose)
+{
+       u32 bus = 0;
+       u32 val, dev, func, offset;
+
+       /* Currently we have only 2 device connected - up-to 32 devices */
+       for (dev = 0; dev < 2; dev++) {
+               /* List only first function number - up-to 8 functions */
+               for (func = 0; func < 1; func++) {
+                       printk(KERN_INFO "%02x:%02x:%02x", bus, dev, func);
+                       /* read the first 64 standardized bytes */
+                       /* Up-to 192 bytes can be list of capabilities */
+                       for (offset = 0; offset < 64; offset += 4) {
+                               early_read_config_dword(hose, bus,
+                                       PCI_DEVFN(dev, func), offset, &val);
+                               if (offset == 0 && val == 0xFFFFFFFF) {
+                                       printk(KERN_CONT "\nABSENT");
+                                       break;
+                               }
+                               if (!(offset % 0x10))
+                                       printk(KERN_CONT "\n%04x:    ", offset);
+
+                               printk(KERN_CONT "%08x  ", val);
+                       }
+                       printk(KERN_INFO "\n");
+               }
+       }
+}
+#else
+void __init xilinx_early_pci_scan(struct pci_controller *hose)
+{
+}
+#endif
+
+/**
+ * xilinx_pci_init - Find and register a Xilinx PCI host bridge
+ */
+void __init xilinx_pci_init(void)
+{
+       struct pci_controller *hose;
+       struct resource r;
+       void __iomem *pci_reg;
+       struct device_node *pci_node;
+
+       pci_node = of_find_matching_node(NULL, xilinx_pci_match);
+       if (!pci_node)
+               return;
+
+       if (of_address_to_resource(pci_node, 0, &r)) {
+               pr_err("xilinx-pci: cannot resolve base address\n");
+               return;
+       }
+
+       hose = pcibios_alloc_controller(pci_node);
+       if (!hose) {
+               pr_err("xilinx-pci: pcibios_alloc_controller() failed\n");
+               return;
+       }
+
+       /* Setup config space */
+       setup_indirect_pci(hose, r.start + XPLB_PCI_ADDR,
+                          r.start + XPLB_PCI_DATA,
+                          INDIRECT_TYPE_SET_CFG_TYPE);
+
+       /* According to the xilinx plbv46_pci documentation the soft-core starts
+        * a self-init when the bus master enable bit is set. Without this bit
+        * set the pci bus can't be scanned.
+        */
+       early_write_config_word(hose, 0, 0, PCI_COMMAND, PCI_HOST_ENABLE_CMD);
+
+       /* Set the max latency timer to 255 */
+       early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0xff);
+
+       /* Set the max bus number to 255, and bus/subbus no's to 0 */
+       pci_reg = of_iomap(pci_node, 0);
+       out_be32(pci_reg + XPLB_PCI_BUS, 0x000000ff);
+       iounmap(pci_reg);
+
+       /* Register the host bridge with the linux kernel! */
+       pci_process_bridge_OF_ranges(hose, pci_node,
+                                       INDIRECT_TYPE_SET_CFG_TYPE);
+
+       pr_info("xilinx-pci: Registered PCI host bridge\n");
+       xilinx_early_pci_scan(hose);
+}