microblaze: Enable PCI, missing files
authorMichal Simek <monstr@monstr.eu>
Mon, 18 Jan 2010 14:27:10 +0000 (15:27 +0100)
committerMichal Simek <monstr@monstr.eu>
Thu, 11 Mar 2010 13:04:27 +0000 (14:04 +0100)
There are two parts of changes. The first is just enable
PCI in Makefiles and in Kconfig. The second is the rest of
missing files. I didn't want to add it with previous patch
because that patch is too big.

Current Microblaze toolchain has problem with weak symbols
that's why is necessary to apply this changes to be possible
to compile pci support.
Xilinx knows about this problem.

Signed-off-by: Michal Simek <monstr@monstr.eu>
arch/microblaze/Kconfig
arch/microblaze/Makefile
arch/microblaze/include/asm/io.h
arch/microblaze/include/asm/pgtable.h
arch/microblaze/include/asm/prom.h
arch/microblaze/pci/Makefile [new file with mode: 0644]
arch/microblaze/pci/indirect_pci.c [new file with mode: 0644]
arch/microblaze/pci/iomap.c [new file with mode: 0644]
drivers/pci/Makefile

index 71ec041..e1fa084 100644 (file)
@@ -256,6 +256,21 @@ source "fs/Kconfig.binfmt"
 
 endmenu
 
+menu "Bus Options"
+
+config PCI
+       bool "PCI support"
+
+config PCI_DOMAINS
+       def_bool PCI
+
+config PCI_SYSCALL
+       def_bool PCI
+
+source "drivers/pci/Kconfig"
+
+endmenu
+
 source "net/Kconfig"
 
 source "drivers/Kconfig"
index d2d6cfc..836832d 100644 (file)
@@ -50,6 +50,7 @@ libs-y += $(LIBGCC)
 core-y += arch/microblaze/kernel/
 core-y += arch/microblaze/mm/
 core-y += arch/microblaze/platform/
+core-$(CONFIG_PCI) += arch/microblaze/pci/
 
 drivers-$(CONFIG_OPROFILE) += arch/microblaze/oprofile/
 
index f82df5d..06d804b 100644 (file)
 #include <linux/mm.h>          /* Get struct page {...} */
 #include <asm-generic/iomap.h>
 
-#define PCI_DRAM_OFFSET 0
+#ifndef CONFIG_PCI
+#define _IO_BASE       0
+#define _ISA_MEM_BASE  0
+#define PCI_DRAM_OFFSET        0
+#else
+#define _IO_BASE       isa_io_base
+#define _ISA_MEM_BASE  isa_mem_base
+#define PCI_DRAM_OFFSET        pci_dram_offset
+#endif
+
+extern unsigned long isa_io_base;
+extern unsigned long pci_io_base;
+extern unsigned long pci_dram_offset;
+
+extern resource_size_t isa_mem_base;
 
 #define IO_SPACE_LIMIT (0xFFFFFFFF)
 
index cc3a4df..1c47f6f 100644 (file)
@@ -90,6 +90,21 @@ static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
 #endif /* __ASSEMBLY__ */
 
 /*
+ * Macro to mark a page protection value as "uncacheable".
+ */
+
+#define _PAGE_CACHE_CTL        (_PAGE_GUARDED | _PAGE_NO_CACHE | \
+                                                       _PAGE_WRITETHRU)
+
+#define pgprot_noncached(prot) \
+                       (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \
+                                       _PAGE_NO_CACHE | _PAGE_GUARDED))
+
+#define pgprot_noncached_wc(prot) \
+                        (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \
+                                                       _PAGE_NO_CACHE))
+
+/*
  * The MicroBlaze MMU is identical to the PPC-40x MMU, and uses a hash
  * table containing PTEs, together with a set of 16 segment registers, to
  * define the virtual to physical address mapping.
index 03f45a9..e7d67a3 100644 (file)
 /* Other Prototypes */
 extern int early_uartlite_console(void);
 
+#ifdef CONFIG_PCI
+/*
+ * PCI <-> OF matching functions
+ * (XXX should these be here?)
+ */
+struct pci_bus;
+struct pci_dev;
+extern int pci_device_from_OF_node(struct device_node *node,
+                                       u8 *bus, u8 *devfn);
+extern struct device_node *pci_busdev_to_OF_node(struct pci_bus *bus,
+                                                       int devfn);
+extern struct device_node *pci_device_to_OF_node(struct pci_dev *dev);
+extern void pci_create_OF_bus_map(void);
+#endif
+
 /*
  * OF address retreival & translation
  */
diff --git a/arch/microblaze/pci/Makefile b/arch/microblaze/pci/Makefile
new file mode 100644 (file)
index 0000000..2b89018
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile
+#
+
+obj-$(CONFIG_PCI)              += pci_32.o pci-common.o indirect_pci.o iomap.o
diff --git a/arch/microblaze/pci/indirect_pci.c b/arch/microblaze/pci/indirect_pci.c
new file mode 100644 (file)
index 0000000..25f18f0
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Support for indirect PCI bridges.
+ *
+ * Copyright (C) 1998 Gabriel Paubert.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+
+static int
+indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+                    int len, u32 *val)
+{
+       struct pci_controller *hose = pci_bus_to_host(bus);
+       volatile void __iomem *cfg_data;
+       u8 cfg_type = 0;
+       u32 bus_no, reg;
+
+       if (hose->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) {
+               if (bus->number != hose->first_busno)
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+               if (devfn != 0)
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+       }
+
+       if (hose->indirect_type & INDIRECT_TYPE_SET_CFG_TYPE)
+               if (bus->number != hose->first_busno)
+                       cfg_type = 1;
+
+       bus_no = (bus->number == hose->first_busno) ?
+                       hose->self_busno : bus->number;
+
+       if (hose->indirect_type & INDIRECT_TYPE_EXT_REG)
+               reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
+       else
+               reg = offset & 0xfc; /* Only 3 bits for function */
+
+       if (hose->indirect_type & INDIRECT_TYPE_BIG_ENDIAN)
+               out_be32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
+                        (devfn << 8) | reg | cfg_type));
+       else
+               out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
+                        (devfn << 8) | reg | cfg_type));
+
+       /*
+        * Note: the caller has already checked that offset is
+        * suitably aligned and that len is 1, 2 or 4.
+        */
+       cfg_data = hose->cfg_data + (offset & 3); /* Only 3 bits for function */
+       switch (len) {
+       case 1:
+               *val = in_8(cfg_data);
+               break;
+       case 2:
+               *val = in_le16(cfg_data);
+               break;
+       default:
+               *val = in_le32(cfg_data);
+               break;
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
+                     int len, u32 val)
+{
+       struct pci_controller *hose = pci_bus_to_host(bus);
+       volatile void __iomem *cfg_data;
+       u8 cfg_type = 0;
+       u32 bus_no, reg;
+
+       if (hose->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) {
+               if (bus->number != hose->first_busno)
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+               if (devfn != 0)
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+       }
+
+       if (hose->indirect_type & INDIRECT_TYPE_SET_CFG_TYPE)
+               if (bus->number != hose->first_busno)
+                       cfg_type = 1;
+
+       bus_no = (bus->number == hose->first_busno) ?
+                       hose->self_busno : bus->number;
+
+       if (hose->indirect_type & INDIRECT_TYPE_EXT_REG)
+               reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
+       else
+               reg = offset & 0xfc;
+
+       if (hose->indirect_type & INDIRECT_TYPE_BIG_ENDIAN)
+               out_be32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
+                        (devfn << 8) | reg | cfg_type));
+       else
+               out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) |
+                        (devfn << 8) | reg | cfg_type));
+
+       /* surpress setting of PCI_PRIMARY_BUS */
+       if (hose->indirect_type & INDIRECT_TYPE_SURPRESS_PRIMARY_BUS)
+               if ((offset == PCI_PRIMARY_BUS) &&
+                       (bus->number == hose->first_busno))
+                       val &= 0xffffff00;
+
+       /* Workaround for PCI_28 Errata in 440EPx/GRx */
+       if ((hose->indirect_type & INDIRECT_TYPE_BROKEN_MRM) &&
+                       offset == PCI_CACHE_LINE_SIZE) {
+               val = 0;
+       }
+
+       /*
+        * Note: the caller has already checked that offset is
+        * suitably aligned and that len is 1, 2 or 4.
+        */
+       cfg_data = hose->cfg_data + (offset & 3);
+       switch (len) {
+       case 1:
+               out_8(cfg_data, val);
+               break;
+       case 2:
+               out_le16(cfg_data, val);
+               break;
+       default:
+               out_le32(cfg_data, val);
+               break;
+       }
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops indirect_pci_ops = {
+       .read = indirect_read_config,
+       .write = indirect_write_config,
+};
+
+void __init
+setup_indirect_pci(struct pci_controller *hose,
+                  resource_size_t cfg_addr,
+                  resource_size_t cfg_data, u32 flags)
+{
+       resource_size_t base = cfg_addr & PAGE_MASK;
+       void __iomem *mbase;
+
+       mbase = ioremap(base, PAGE_SIZE);
+       hose->cfg_addr = mbase + (cfg_addr & ~PAGE_MASK);
+       if ((cfg_data & PAGE_MASK) != base)
+               mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);
+       hose->cfg_data = mbase + (cfg_data & ~PAGE_MASK);
+       hose->ops = &indirect_pci_ops;
+       hose->indirect_type = flags;
+}
diff --git a/arch/microblaze/pci/iomap.c b/arch/microblaze/pci/iomap.c
new file mode 100644 (file)
index 0000000..3fbf16f
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * ppc64 "iomap" interface implementation.
+ *
+ * (C) Copyright 2004 Linus Torvalds
+ */
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
+{
+       resource_size_t start = pci_resource_start(dev, bar);
+       resource_size_t len = pci_resource_len(dev, bar);
+       unsigned long flags = pci_resource_flags(dev, bar);
+
+       if (!len)
+               return NULL;
+       if (max && len > max)
+               len = max;
+       if (flags & IORESOURCE_IO)
+               return ioport_map(start, len);
+       if (flags & IORESOURCE_MEM)
+               return ioremap(start, len);
+       /* What? */
+       return NULL;
+}
+EXPORT_SYMBOL(pci_iomap);
+
+void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+{
+       if (isa_vaddr_is_ioport(addr))
+               return;
+       if (pcibios_vaddr_is_ioport(addr))
+               return;
+       iounmap(addr);
+}
+EXPORT_SYMBOL(pci_iounmap);
index 3d102dd..0b51857 100644 (file)
@@ -48,6 +48,7 @@ obj-$(CONFIG_PPC) += setup-bus.o
 obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
 obj-$(CONFIG_X86_VISWS) += setup-irq.o
 obj-$(CONFIG_MN10300) += setup-bus.o
+obj-$(CONFIG_MICROBLAZE) += setup-bus.o
 
 #
 # ACPI Related PCI FW Functions