diff options
author | Michal Simek <monstr@monstr.eu> | 2010-01-18 15:27:10 +0100 |
---|---|---|
committer | Michal Simek <monstr@monstr.eu> | 2010-03-11 14:04:27 +0100 |
commit | a6475c132278c1be158a13872c233aeab8a00176 (patch) | |
tree | d25967ef6fc4fb408d9c6c7c0582edc9ff4760a3 /arch/microblaze | |
parent | d3afa58c20b65155af9f0d5eaa59fe2d367ac432 (diff) |
microblaze: Enable PCI, missing files
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>
Diffstat (limited to 'arch/microblaze')
-rw-r--r-- | arch/microblaze/Kconfig | 15 | ||||
-rw-r--r-- | arch/microblaze/Makefile | 1 | ||||
-rw-r--r-- | arch/microblaze/include/asm/io.h | 16 | ||||
-rw-r--r-- | arch/microblaze/include/asm/pgtable.h | 15 | ||||
-rw-r--r-- | arch/microblaze/include/asm/prom.h | 15 | ||||
-rw-r--r-- | arch/microblaze/pci/Makefile | 5 | ||||
-rw-r--r-- | arch/microblaze/pci/indirect_pci.c | 163 | ||||
-rw-r--r-- | arch/microblaze/pci/iomap.c | 39 |
8 files changed, 268 insertions, 1 deletions
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 71ec04137417..e1fa0844ba4e 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -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" diff --git a/arch/microblaze/Makefile b/arch/microblaze/Makefile index d2d6cfcb1a30..836832dd9b26 100644 --- a/arch/microblaze/Makefile +++ b/arch/microblaze/Makefile @@ -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/ diff --git a/arch/microblaze/include/asm/io.h b/arch/microblaze/include/asm/io.h index f82df5d221a8..06d804b15a51 100644 --- a/arch/microblaze/include/asm/io.h +++ b/arch/microblaze/include/asm/io.h @@ -17,7 +17,21 @@ #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) diff --git a/arch/microblaze/include/asm/pgtable.h b/arch/microblaze/include/asm/pgtable.h index cc3a4dfc3eaa..1c47f6f8bfb6 100644 --- a/arch/microblaze/include/asm/pgtable.h +++ b/arch/microblaze/include/asm/pgtable.h @@ -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. diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h index 03f45a963204..e7d67a329bd7 100644 --- a/arch/microblaze/include/asm/prom.h +++ b/arch/microblaze/include/asm/prom.h @@ -31,6 +31,21 @@ /* 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 index 000000000000..2b8901864b23 --- /dev/null +++ b/arch/microblaze/pci/Makefile @@ -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 index 000000000000..25f18f017f21 --- /dev/null +++ b/arch/microblaze/pci/indirect_pci.c @@ -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 index 000000000000..3fbf16f4e16c --- /dev/null +++ b/arch/microblaze/pci/iomap.c @@ -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); |