diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-03-02 07:44:16 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-03-02 07:44:16 -0800 | 
| commit | aebb2afd5420c860b7fbc3882a323ef1247fbf16 (patch) | |
| tree | 05ee0efcebca5ec421de44de7a6d6271088c64a8 /arch/mips/pci/pci-xlp.c | |
| parent | 8eae508b7c6ff502a71d0293b69e97c5505d5840 (diff) | |
| parent | edb15d83a875a1f4b1576188844db5c330c3267d (diff) | |
| download | olio-linux-3.10-aebb2afd5420c860b7fbc3882a323ef1247fbf16.tar.xz olio-linux-3.10-aebb2afd5420c860b7fbc3882a323ef1247fbf16.zip  | |
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle:
 o Add basic support for the Mediatek/Ralink Wireless SoC family.
 o The Qualcomm Atheros platform is extended by support for the new
   QCA955X SoC series as well as a bunch of patches that get the code
   ready for OF support.
 o Lantiq and BCM47XX platform have a few improvements and bug fixes.
 o MIPS has sent a few patches that get the kernel ready for the
   upcoming microMIPS support.
 o The rest of the series is made up of small bug fixes and cleanups
   that relate to various parts of the MIPS code.  The biggy in there is
   a whitespace cleanup.  After I was sent another set of whitespace
   cleanup patches I decided it was the time to clean the whitespace
   "issues" for once and and that touches many files below arch/mips/.
Fix up silly conflicts, mostly due to whitespace cleanups.
* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (105 commits)
  MIPS: Quit exporting kernel internel break codes to uapi/asm/break.h
  MIPS: remove broken conditional inside vpe loader code
  MIPS: SMTC: fix implicit declaration of set_vi_handler
  MIPS: early_printk: drop __init annotations
  MIPS: Probe for and report hardware virtualization support.
  MIPS: ath79: add support for the Qualcomm Atheros AP136-010 board
  MIPS: ath79: add USB controller registration code for the QCA955X SoCs
  MIPS: ath79: add PCI controller registration code for the QCA955X SoCs
  MIPS: ath79: add WMAC registration code for the QCA955X SoCs
  MIPS: ath79: register UART for the QCA955X SoCs
  MIPS: ath79: add QCA955X specific glue to ath79_device_reset_{set, clear}
  MIPS: ath79: add GPIO setup code for the QCA955X SoCs
  MIPS: ath79: add IRQ handling code for the QCA955X SoCs
  MIPS: ath79: add clock setup code for the QCA955X SoCs
  MIPS: ath79: add SoC detection code for the QCA955X SoCs
  MIPS: ath79: add early printk support for the QCA955X SoCs
  MIPS: ath79: fix WMAC IRQ resource assignment
  mips: reserve elfcorehdr
  mips: Make sure kernel memory is in iomem
  MIPS: ath79: use dynamically allocated USB platform devices
  ...
Diffstat (limited to 'arch/mips/pci/pci-xlp.c')
| -rw-r--r-- | arch/mips/pci/pci-xlp.c | 156 | 
1 files changed, 96 insertions, 60 deletions
diff --git a/arch/mips/pci/pci-xlp.c b/arch/mips/pci/pci-xlp.c index 140557a2048..653d2db9e0c 100644 --- a/arch/mips/pci/pci-xlp.c +++ b/arch/mips/pci/pci-xlp.c @@ -46,6 +46,7 @@  #include <asm/netlogic/interrupt.h>  #include <asm/netlogic/haldefs.h> +#include <asm/netlogic/common.h>  #include <asm/netlogic/xlp-hal/iomap.h>  #include <asm/netlogic/xlp-hal/pic.h> @@ -55,7 +56,7 @@  static void *pci_config_base; -#define	pci_cfg_addr(bus, devfn, off) (((bus) << 20) | ((devfn) << 12) | (off)) +#define pci_cfg_addr(bus, devfn, off) (((bus) << 20) | ((devfn) << 12) | (off))  /* PCI ops */  static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn, @@ -64,8 +65,12 @@ static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn,  	u32 data;  	u32 *cfgaddr; +	where &= ~3; +	if (bus->number == 0 && PCI_SLOT(devfn) == 1 && where == 0x954) +		return 0xffffffff; +  	cfgaddr = (u32 *)(pci_config_base + -			pci_cfg_addr(bus->number, devfn, where & ~3)); +			pci_cfg_addr(bus->number, devfn, where));  	data = *cfgaddr;  	return data;  } @@ -135,54 +140,60 @@ struct pci_ops nlm_pci_ops = {  };  static struct resource nlm_pci_mem_resource = { -	.name           = "XLP PCI MEM", -	.start          = 0xd0000000UL,	/* 256MB PCI mem @ 0xd000_0000 */ -	.end            = 0xdfffffffUL, -	.flags          = IORESOURCE_MEM, +	.name		= "XLP PCI MEM", +	.start		= 0xd0000000UL, /* 256MB PCI mem @ 0xd000_0000 */ +	.end		= 0xdfffffffUL, +	.flags		= IORESOURCE_MEM,  };  static struct resource nlm_pci_io_resource = { -	.name           = "XLP IO MEM", -	.start          = 0x14000000UL,	/* 64MB PCI IO @ 0x1000_0000 */ -	.end            = 0x17ffffffUL, -	.flags          = IORESOURCE_IO, +	.name		= "XLP IO MEM", +	.start		= 0x14000000UL, /* 64MB PCI IO @ 0x1000_0000 */ +	.end		= 0x17ffffffUL, +	.flags		= IORESOURCE_IO,  };  struct pci_controller nlm_pci_controller = { -	.index          = 0, -	.pci_ops        = &nlm_pci_ops, -	.mem_resource   = &nlm_pci_mem_resource, -	.mem_offset     = 0x00000000UL, -	.io_resource    = &nlm_pci_io_resource, -	.io_offset      = 0x00000000UL, +	.index		= 0, +	.pci_ops	= &nlm_pci_ops, +	.mem_resource	= &nlm_pci_mem_resource, +	.mem_offset	= 0x00000000UL, +	.io_resource	= &nlm_pci_io_resource, +	.io_offset	= 0x00000000UL,  }; -static int get_irq_vector(const struct pci_dev *dev) +static struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev)  { -	/* -	 * For XLP PCIe, there is an IRQ per Link, find out which -	 * link the device is on to assign interrupts -	*/ -	if (dev->bus->self == NULL) -		return 0; +	struct pci_bus *bus, *p; -	switch	(dev->bus->self->devfn) { -	case 0x8: -		return PIC_PCIE_LINK_0_IRQ; -	case 0x9: -		return PIC_PCIE_LINK_1_IRQ; -	case 0xa: -		return PIC_PCIE_LINK_2_IRQ; -	case 0xb: -		return PIC_PCIE_LINK_3_IRQ; -	} -	WARN(1, "Unexpected devfn %d\n", dev->bus->self->devfn); -	return 0; +	/* Find the bridge on bus 0 */ +	bus = dev->bus; +	for (p = bus->parent; p && p->number != 0; p = p->parent) +		bus = p; + +	return p ? bus->self : NULL; +} + +static inline int nlm_pci_link_to_irq(int link) +{ +	return PIC_PCIE_LINK_0_IRQ + link;  }  int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)  { -	return get_irq_vector(dev); +	struct pci_dev *lnkdev; +	int lnkslot, lnkfunc; + +	/* +	 * For XLP PCIe, there is an IRQ per Link, find out which +	 * link the device is on to assign interrupts +	*/ +	lnkdev = xlp_get_pcie_link(dev); +	if (lnkdev == NULL) +		return 0; +	lnkfunc = PCI_FUNC(lnkdev->devfn); +	lnkslot = PCI_SLOT(lnkdev->devfn); +	return nlm_irq_to_xirq(lnkslot / 8, nlm_pci_link_to_irq(lnkfunc));  }  /* Do platform specific device initialization at pci_enable_device() time */ @@ -191,51 +202,76 @@ int pcibios_plat_dev_init(struct pci_dev *dev)  	return 0;  } -static int xlp_enable_pci_bswap(void) +/* + * If big-endian, enable hardware byteswap on the PCIe bridges. + * This will make both the SoC and PCIe devices behave consistently with + * readl/writel. + */ +#ifdef __BIG_ENDIAN +static void xlp_config_pci_bswap(int node, int link)  { -	uint64_t pciebase, sysbase; -	int node, i; +	uint64_t nbubase, lnkbase;  	u32 reg; -	/* Chip-0 so node set to 0 */ -	node = 0; -	sysbase = nlm_get_bridge_regbase(node); +	nbubase = nlm_get_bridge_regbase(node); +	lnkbase = nlm_get_pcie_base(node, link); +  	/*  	 *  Enable byte swap in hardware. Program each link's PCIe SWAP regions  	 * from the link's address ranges.  	 */ -	for (i = 0; i < 4; i++) { -		pciebase = nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node, i)); -		if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff) -			continue; +	reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link); +	nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg); -		reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEMEM_BASE0 + i); -		nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_MEM_BASE, reg); +	reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_LIMIT0 + link); +	nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff); -		reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEMEM_LIMIT0 + i); -		nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_MEM_LIM, -			reg | 0xfff); +	reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_BASE0 + link); +	nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg); -		reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEIO_BASE0 + i); -		nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_IO_BASE, reg); - -		reg = nlm_read_bridge_reg(sysbase, BRIDGE_PCIEIO_LIMIT0 + i); -		nlm_write_pci_reg(pciebase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff); -	} -	return 0; +	reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_LIMIT0 + link); +	nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff);  } +#else +/* Swap configuration not needed in little-endian mode */ +static inline void xlp_config_pci_bswap(int node, int link) {} +#endif /* __BIG_ENDIAN */  static int __init pcibios_init(void)  { +	struct nlm_soc_info *nodep; +	uint64_t pciebase; +	int link, n; +	u32 reg; +  	/* Firmware assigns PCI resources */  	pci_set_flags(PCI_PROBE_ONLY);  	pci_config_base = ioremap(XLP_DEFAULT_PCI_ECFG_BASE, 64 << 20);  	/* Extend IO port for memory mapped io */ -	ioport_resource.start =  0; +	ioport_resource.start =	 0;  	ioport_resource.end   = ~0; -	xlp_enable_pci_bswap(); +	for (n = 0; n < NLM_NR_NODES; n++) { +		nodep = nlm_get_node(n); +		if (!nodep->coremask) +			continue;	/* node does not exist */ + +		for (link = 0; link < 4; link++) { +			pciebase = nlm_get_pcie_base(n, link); +			if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff) +				continue; +			xlp_config_pci_bswap(n, link); + +			/* put in intpin and irq - u-boot does not */ +			reg = nlm_read_pci_reg(pciebase, 0xf); +			reg &= ~0x1fu; +			reg |= (1 << 8) | nlm_pci_link_to_irq(link); +			nlm_write_pci_reg(pciebase, 0xf, reg); +			pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link); +		} +	} +  	set_io_port_base(CKSEG1);  	nlm_pci_controller.io_map_base = CKSEG1;  |