diff options
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); |