diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2013-02-21 15:51:33 +0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2013-02-21 15:51:33 +0400 |
commit | 8bfc245f9ad7bd4e461179e4e7852ef99b8b6144 (patch) | |
tree | 0ad091f645fbc8318634599d278966a53d3922ee /arch/mips/pci | |
parent | 612663a974065c3445e641d046769fe4c55a6438 (diff) | |
parent | 535237cecab2b078114be712c67e89a0db61965f (diff) | |
download | linux-8bfc245f9ad7bd4e461179e4e7852ef99b8b6144.tar.xz |
Merge branch 'mips-next-3.9' of git://git.linux-mips.org/pub/scm/john/linux-john into mips-for-linux-next
Diffstat (limited to 'arch/mips/pci')
-rw-r--r-- | arch/mips/pci/pci-ar71xx.c | 194 | ||||
-rw-r--r-- | arch/mips/pci/pci-ar724x.c | 304 | ||||
-rw-r--r-- | arch/mips/pci/pci-lantiq.c | 12 | ||||
-rw-r--r-- | arch/mips/pci/pci-xlp.c | 124 | ||||
-rw-r--r-- | arch/mips/pci/pci.c | 15 |
5 files changed, 445 insertions, 204 deletions
diff --git a/arch/mips/pci/pci-ar71xx.c b/arch/mips/pci/pci-ar71xx.c index 6eaa4f2d0e38..412ec025cf55 100644 --- a/arch/mips/pci/pci-ar71xx.c +++ b/arch/mips/pci/pci-ar71xx.c @@ -18,26 +18,11 @@ #include <linux/pci.h> #include <linux/pci_regs.h> #include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/platform_device.h> #include <asm/mach-ath79/ar71xx_regs.h> #include <asm/mach-ath79/ath79.h> -#include <asm/mach-ath79/pci.h> - -#define AR71XX_PCI_MEM_BASE 0x10000000 -#define AR71XX_PCI_MEM_SIZE 0x07000000 - -#define AR71XX_PCI_WIN0_OFFS 0x10000000 -#define AR71XX_PCI_WIN1_OFFS 0x11000000 -#define AR71XX_PCI_WIN2_OFFS 0x12000000 -#define AR71XX_PCI_WIN3_OFFS 0x13000000 -#define AR71XX_PCI_WIN4_OFFS 0x14000000 -#define AR71XX_PCI_WIN5_OFFS 0x15000000 -#define AR71XX_PCI_WIN6_OFFS 0x16000000 -#define AR71XX_PCI_WIN7_OFFS 0x07000000 - -#define AR71XX_PCI_CFG_BASE \ - (AR71XX_PCI_MEM_BASE + AR71XX_PCI_WIN7_OFFS + 0x10000) -#define AR71XX_PCI_CFG_SIZE 0x100 #define AR71XX_PCI_REG_CRP_AD_CBE 0x00 #define AR71XX_PCI_REG_CRP_WRDATA 0x04 @@ -63,8 +48,15 @@ #define AR71XX_PCI_IRQ_COUNT 5 -static DEFINE_SPINLOCK(ar71xx_pci_lock); -static void __iomem *ar71xx_pcicfg_base; +struct ar71xx_pci_controller { + void __iomem *cfg_base; + spinlock_t lock; + int irq; + int irq_base; + struct pci_controller pci_ctrl; + struct resource io_res; + struct resource mem_res; +}; /* Byte lane enable bits */ static const u8 ar71xx_pci_ble_table[4][4] = { @@ -107,9 +99,18 @@ static inline u32 ar71xx_pci_bus_addr(struct pci_bus *bus, unsigned int devfn, return ret; } -static int ar71xx_pci_check_error(int quiet) +static inline struct ar71xx_pci_controller * +pci_bus_to_ar71xx_controller(struct pci_bus *bus) { - void __iomem *base = ar71xx_pcicfg_base; + struct pci_controller *hose; + + hose = (struct pci_controller *) bus->sysdata; + return container_of(hose, struct ar71xx_pci_controller, pci_ctrl); +} + +static int ar71xx_pci_check_error(struct ar71xx_pci_controller *apc, int quiet) +{ + void __iomem *base = apc->cfg_base; u32 pci_err; u32 ahb_err; @@ -144,9 +145,10 @@ static int ar71xx_pci_check_error(int quiet) return !!(ahb_err | pci_err); } -static inline void ar71xx_pci_local_write(int where, int size, u32 value) +static inline void ar71xx_pci_local_write(struct ar71xx_pci_controller *apc, + int where, int size, u32 value) { - void __iomem *base = ar71xx_pcicfg_base; + void __iomem *base = apc->cfg_base; u32 ad_cbe; value = value << (8 * (where & 3)); @@ -162,7 +164,8 @@ static inline int ar71xx_pci_set_cfgaddr(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 cmd) { - void __iomem *base = ar71xx_pcicfg_base; + struct ar71xx_pci_controller *apc = pci_bus_to_ar71xx_controller(bus); + void __iomem *base = apc->cfg_base; u32 addr; addr = ar71xx_pci_bus_addr(bus, devfn, where); @@ -171,13 +174,14 @@ static inline int ar71xx_pci_set_cfgaddr(struct pci_bus *bus, __raw_writel(cmd | ar71xx_pci_get_ble(where, size, 0), base + AR71XX_PCI_REG_CFG_CBE); - return ar71xx_pci_check_error(1); + return ar71xx_pci_check_error(apc, 1); } static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { - void __iomem *base = ar71xx_pcicfg_base; + struct ar71xx_pci_controller *apc = pci_bus_to_ar71xx_controller(bus); + void __iomem *base = apc->cfg_base; unsigned long flags; u32 data; int err; @@ -186,7 +190,7 @@ static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, ret = PCIBIOS_SUCCESSFUL; data = ~0; - spin_lock_irqsave(&ar71xx_pci_lock, flags); + spin_lock_irqsave(&apc->lock, flags); err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size, AR71XX_PCI_CFG_CMD_READ); @@ -195,7 +199,7 @@ static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, else data = __raw_readl(base + AR71XX_PCI_REG_CFG_RDDATA); - spin_unlock_irqrestore(&ar71xx_pci_lock, flags); + spin_unlock_irqrestore(&apc->lock, flags); *value = (data >> (8 * (where & 3))) & ar71xx_pci_read_mask[size & 7]; @@ -205,7 +209,8 @@ static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, static int ar71xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { - void __iomem *base = ar71xx_pcicfg_base; + struct ar71xx_pci_controller *apc = pci_bus_to_ar71xx_controller(bus); + void __iomem *base = apc->cfg_base; unsigned long flags; int err; int ret; @@ -213,7 +218,7 @@ static int ar71xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, value = value << (8 * (where & 3)); ret = PCIBIOS_SUCCESSFUL; - spin_lock_irqsave(&ar71xx_pci_lock, flags); + spin_lock_irqsave(&apc->lock, flags); err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size, AR71XX_PCI_CFG_CMD_WRITE); @@ -222,7 +227,7 @@ static int ar71xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, else __raw_writel(value, base + AR71XX_PCI_REG_CFG_WRDATA); - spin_unlock_irqrestore(&ar71xx_pci_lock, flags); + spin_unlock_irqrestore(&apc->lock, flags); return ret; } @@ -232,45 +237,28 @@ static struct pci_ops ar71xx_pci_ops = { .write = ar71xx_pci_write_config, }; -static struct resource ar71xx_pci_io_resource = { - .name = "PCI IO space", - .start = 0, - .end = 0, - .flags = IORESOURCE_IO, -}; - -static struct resource ar71xx_pci_mem_resource = { - .name = "PCI memory space", - .start = AR71XX_PCI_MEM_BASE, - .end = AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1, - .flags = IORESOURCE_MEM -}; - -static struct pci_controller ar71xx_pci_controller = { - .pci_ops = &ar71xx_pci_ops, - .mem_resource = &ar71xx_pci_mem_resource, - .io_resource = &ar71xx_pci_io_resource, -}; - static void ar71xx_pci_irq_handler(unsigned int irq, struct irq_desc *desc) { + struct ar71xx_pci_controller *apc; void __iomem *base = ath79_reset_base; u32 pending; + apc = irq_get_handler_data(irq); + pending = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_STATUS) & __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); if (pending & AR71XX_PCI_INT_DEV0) - generic_handle_irq(ATH79_PCI_IRQ(0)); + generic_handle_irq(apc->irq_base + 0); else if (pending & AR71XX_PCI_INT_DEV1) - generic_handle_irq(ATH79_PCI_IRQ(1)); + generic_handle_irq(apc->irq_base + 1); else if (pending & AR71XX_PCI_INT_DEV2) - generic_handle_irq(ATH79_PCI_IRQ(2)); + generic_handle_irq(apc->irq_base + 2); else if (pending & AR71XX_PCI_INT_CORE) - generic_handle_irq(ATH79_PCI_IRQ(4)); + generic_handle_irq(apc->irq_base + 4); else spurious_interrupt(); @@ -278,10 +266,14 @@ static void ar71xx_pci_irq_handler(unsigned int irq, struct irq_desc *desc) static void ar71xx_pci_irq_unmask(struct irq_data *d) { - unsigned int irq = d->irq - ATH79_PCI_IRQ_BASE; + struct ar71xx_pci_controller *apc; + unsigned int irq; void __iomem *base = ath79_reset_base; u32 t; + apc = irq_data_get_irq_chip_data(d); + irq = d->irq - apc->irq_base; + t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE); @@ -291,10 +283,14 @@ static void ar71xx_pci_irq_unmask(struct irq_data *d) static void ar71xx_pci_irq_mask(struct irq_data *d) { - unsigned int irq = d->irq - ATH79_PCI_IRQ_BASE; + struct ar71xx_pci_controller *apc; + unsigned int irq; void __iomem *base = ath79_reset_base; u32 t; + apc = irq_data_get_irq_chip_data(d); + irq = d->irq - apc->irq_base; + t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE); @@ -309,7 +305,7 @@ static struct irq_chip ar71xx_pci_irq_chip = { .irq_mask_ack = ar71xx_pci_irq_mask, }; -static __init void ar71xx_pci_irq_init(void) +static void ar71xx_pci_irq_init(struct ar71xx_pci_controller *apc) { void __iomem *base = ath79_reset_base; int i; @@ -319,15 +315,19 @@ static __init void ar71xx_pci_irq_init(void) BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR71XX_PCI_IRQ_COUNT); - for (i = ATH79_PCI_IRQ_BASE; - i < ATH79_PCI_IRQ_BASE + AR71XX_PCI_IRQ_COUNT; i++) + apc->irq_base = ATH79_PCI_IRQ_BASE; + for (i = apc->irq_base; + i < apc->irq_base + AR71XX_PCI_IRQ_COUNT; i++) { irq_set_chip_and_handler(i, &ar71xx_pci_irq_chip, handle_level_irq); + irq_set_chip_data(i, apc); + } - irq_set_chained_handler(ATH79_CPU_IRQ_IP2, ar71xx_pci_irq_handler); + irq_set_handler_data(apc->irq, apc); + irq_set_chained_handler(apc->irq, ar71xx_pci_irq_handler); } -static __init void ar71xx_pci_reset(void) +static void ar71xx_pci_reset(void) { void __iomem *ddr_base = ath79_ddr_base; @@ -349,27 +349,83 @@ static __init void ar71xx_pci_reset(void) mdelay(100); } -__init int ar71xx_pcibios_init(void) +static int ar71xx_pci_probe(struct platform_device *pdev) { + struct ar71xx_pci_controller *apc; + struct resource *res; u32 t; - ar71xx_pcicfg_base = ioremap(AR71XX_PCI_CFG_BASE, AR71XX_PCI_CFG_SIZE); - if (ar71xx_pcicfg_base == NULL) + apc = devm_kzalloc(&pdev->dev, sizeof(struct ar71xx_pci_controller), + GFP_KERNEL); + if (!apc) + return -ENOMEM; + + spin_lock_init(&apc->lock); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_base"); + if (!res) + return -EINVAL; + + apc->cfg_base = devm_request_and_ioremap(&pdev->dev, res); + if (!apc->cfg_base) return -ENOMEM; + apc->irq = platform_get_irq(pdev, 0); + if (apc->irq < 0) + return -EINVAL; + + res = platform_get_resource_byname(pdev, IORESOURCE_IO, "io_base"); + if (!res) + return -EINVAL; + + apc->io_res.parent = res; + apc->io_res.name = "PCI IO space"; + apc->io_res.start = res->start; + apc->io_res.end = res->end; + apc->io_res.flags = IORESOURCE_IO; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem_base"); + if (!res) + return -EINVAL; + + apc->mem_res.parent = res; + apc->mem_res.name = "PCI memory space"; + apc->mem_res.start = res->start; + apc->mem_res.end = res->end; + apc->mem_res.flags = IORESOURCE_MEM; + ar71xx_pci_reset(); /* setup COMMAND register */ t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK; - ar71xx_pci_local_write(PCI_COMMAND, 4, t); + ar71xx_pci_local_write(apc, PCI_COMMAND, 4, t); /* clear bus errors */ - ar71xx_pci_check_error(1); + ar71xx_pci_check_error(apc, 1); + + ar71xx_pci_irq_init(apc); - ar71xx_pci_irq_init(); + apc->pci_ctrl.pci_ops = &ar71xx_pci_ops; + apc->pci_ctrl.mem_resource = &apc->mem_res; + apc->pci_ctrl.io_resource = &apc->io_res; - register_pci_controller(&ar71xx_pci_controller); + register_pci_controller(&apc->pci_ctrl); return 0; } + +static struct platform_driver ar71xx_pci_driver = { + .probe = ar71xx_pci_probe, + .driver = { + .name = "ar71xx-pci", + .owner = THIS_MODULE, + }, +}; + +static int __init ar71xx_pci_init(void) +{ + return platform_driver_register(&ar71xx_pci_driver); +} + +postcore_initcall(ar71xx_pci_init); diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c index 279585d6eca0..8a0700d448fe 100644 --- a/arch/mips/pci/pci-ar724x.c +++ b/arch/mips/pci/pci-ar724x.c @@ -9,19 +9,13 @@ * by the Free Software Foundation. */ +#include <linux/spinlock.h> #include <linux/irq.h> #include <linux/pci.h> +#include <linux/module.h> +#include <linux/platform_device.h> #include <asm/mach-ath79/ath79.h> #include <asm/mach-ath79/ar71xx_regs.h> -#include <asm/mach-ath79/pci.h> - -#define AR724X_PCI_CFG_BASE 0x14000000 -#define AR724X_PCI_CFG_SIZE 0x1000 -#define AR724X_PCI_CTRL_BASE (AR71XX_APB_BASE + 0x000f0000) -#define AR724X_PCI_CTRL_SIZE 0x100 - -#define AR724X_PCI_MEM_BASE 0x10000000 -#define AR724X_PCI_MEM_SIZE 0x04000000 #define AR724X_PCI_REG_RESET 0x18 #define AR724X_PCI_REG_INT_STATUS 0x4c @@ -35,38 +29,112 @@ #define AR7240_BAR0_WAR_VALUE 0xffff -static DEFINE_SPINLOCK(ar724x_pci_lock); -static void __iomem *ar724x_pci_devcfg_base; -static void __iomem *ar724x_pci_ctrl_base; +#define AR724X_PCI_CMD_INIT (PCI_COMMAND_MEMORY | \ + PCI_COMMAND_MASTER | \ + PCI_COMMAND_INVALIDATE | \ + PCI_COMMAND_PARITY | \ + PCI_COMMAND_SERR | \ + PCI_COMMAND_FAST_BACK) + +struct ar724x_pci_controller { + void __iomem *devcfg_base; + void __iomem *ctrl_base; + void __iomem *crp_base; + + int irq; + int irq_base; + + bool link_up; + bool bar0_is_cached; + u32 bar0_value; -static u32 ar724x_pci_bar0_value; -static bool ar724x_pci_bar0_is_cached; -static bool ar724x_pci_link_up; + spinlock_t lock; -static inline bool ar724x_pci_check_link(void) + struct pci_controller pci_controller; + struct resource io_res; + struct resource mem_res; +}; + +static inline bool ar724x_pci_check_link(struct ar724x_pci_controller *apc) { u32 reset; - reset = __raw_readl(ar724x_pci_ctrl_base + AR724X_PCI_REG_RESET); + reset = __raw_readl(apc->ctrl_base + AR724X_PCI_REG_RESET); return reset & AR724X_PCI_RESET_LINK_UP; } +static inline struct ar724x_pci_controller * +pci_bus_to_ar724x_controller(struct pci_bus *bus) +{ + struct pci_controller *hose; + + hose = (struct pci_controller *) bus->sysdata; + return container_of(hose, struct ar724x_pci_controller, pci_controller); +} + +static int ar724x_pci_local_write(struct ar724x_pci_controller *apc, + int where, int size, u32 value) +{ + unsigned long flags; + void __iomem *base; + u32 data; + int s; + + WARN_ON(where & (size - 1)); + + if (!apc->link_up) + return PCIBIOS_DEVICE_NOT_FOUND; + + base = apc->crp_base; + + spin_lock_irqsave(&apc->lock, flags); + data = __raw_readl(base + (where & ~3)); + + switch (size) { + case 1: + s = ((where & 3) * 8); + data &= ~(0xff << s); + data |= ((value & 0xff) << s); + break; + case 2: + s = ((where & 2) * 8); + data &= ~(0xffff << s); + data |= ((value & 0xffff) << s); + break; + case 4: + data = value; + break; + default: + spin_unlock_irqrestore(&apc->lock, flags); + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + __raw_writel(data, base + (where & ~3)); + /* flush write */ + __raw_readl(base + (where & ~3)); + spin_unlock_irqrestore(&apc->lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, uint32_t *value) { + struct ar724x_pci_controller *apc; unsigned long flags; void __iomem *base; u32 data; - if (!ar724x_pci_link_up) + apc = pci_bus_to_ar724x_controller(bus); + if (!apc->link_up) return PCIBIOS_DEVICE_NOT_FOUND; if (devfn) return PCIBIOS_DEVICE_NOT_FOUND; - base = ar724x_pci_devcfg_base; + base = apc->devcfg_base; - spin_lock_irqsave(&ar724x_pci_lock, flags); + spin_lock_irqsave(&apc->lock, flags); data = __raw_readl(base + (where & ~3)); switch (size) { @@ -85,17 +153,17 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, case 4: break; default: - spin_unlock_irqrestore(&ar724x_pci_lock, flags); + spin_unlock_irqrestore(&apc->lock, flags); return PCIBIOS_BAD_REGISTER_NUMBER; } - spin_unlock_irqrestore(&ar724x_pci_lock, flags); + spin_unlock_irqrestore(&apc->lock, flags); if (where == PCI_BASE_ADDRESS_0 && size == 4 && - ar724x_pci_bar0_is_cached) { + apc->bar0_is_cached) { /* use the cached value */ - *value = ar724x_pci_bar0_value; + *value = apc->bar0_value; } else { *value = data; } @@ -106,12 +174,14 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, uint32_t value) { + struct ar724x_pci_controller *apc; unsigned long flags; void __iomem *base; u32 data; int s; - if (!ar724x_pci_link_up) + apc = pci_bus_to_ar724x_controller(bus); + if (!apc->link_up) return PCIBIOS_DEVICE_NOT_FOUND; if (devfn) @@ -129,18 +199,18 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, * BAR0 register in order to make the device memory * accessible. */ - ar724x_pci_bar0_is_cached = true; - ar724x_pci_bar0_value = value; + apc->bar0_is_cached = true; + apc->bar0_value = value; value = AR7240_BAR0_WAR_VALUE; } else { - ar724x_pci_bar0_is_cached = false; + apc->bar0_is_cached = false; } } - base = ar724x_pci_devcfg_base; + base = apc->devcfg_base; - spin_lock_irqsave(&ar724x_pci_lock, flags); + spin_lock_irqsave(&apc->lock, flags); data = __raw_readl(base + (where & ~3)); switch (size) { @@ -158,7 +228,7 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, data = value; break; default: - spin_unlock_irqrestore(&ar724x_pci_lock, flags); + spin_unlock_irqrestore(&apc->lock, flags); return PCIBIOS_BAD_REGISTER_NUMBER; } @@ -166,7 +236,7 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, __raw_writel(data, base + (where & ~3)); /* flush write */ __raw_readl(base + (where & ~3)); - spin_unlock_irqrestore(&ar724x_pci_lock, flags); + spin_unlock_irqrestore(&apc->lock, flags); return PCIBIOS_SUCCESSFUL; } @@ -176,38 +246,20 @@ static struct pci_ops ar724x_pci_ops = { .write = ar724x_pci_write, }; -static struct resource ar724x_io_resource = { - .name = "PCI IO space", - .start = 0, - .end = 0, - .flags = IORESOURCE_IO, -}; - -static struct resource ar724x_mem_resource = { - .name = "PCI memory space", - .start = AR724X_PCI_MEM_BASE, - .end = AR724X_PCI_MEM_BASE + AR724X_PCI_MEM_SIZE - 1, - .flags = IORESOURCE_MEM, -}; - -static struct pci_controller ar724x_pci_controller = { - .pci_ops = &ar724x_pci_ops, - .io_resource = &ar724x_io_resource, - .mem_resource = &ar724x_mem_resource, -}; - static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc) { + struct ar724x_pci_controller *apc; void __iomem *base; u32 pending; - base = ar724x_pci_ctrl_base; + apc = irq_get_handler_data(irq); + base = apc->ctrl_base; pending = __raw_readl(base + AR724X_PCI_REG_INT_STATUS) & __raw_readl(base + AR724X_PCI_REG_INT_MASK); if (pending & AR724X_PCI_INT_DEV0) - generic_handle_irq(ATH79_PCI_IRQ(0)); + generic_handle_irq(apc->irq_base + 0); else spurious_interrupt(); @@ -215,13 +267,17 @@ static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc) static void ar724x_pci_irq_unmask(struct irq_data *d) { + struct ar724x_pci_controller *apc; void __iomem *base; + int offset; u32 t; - base = ar724x_pci_ctrl_base; + apc = irq_data_get_irq_chip_data(d); + base = apc->ctrl_base; + offset = apc->irq_base - d->irq; - switch (d->irq) { - case ATH79_PCI_IRQ(0): + switch (offset) { + case 0: t = __raw_readl(base + AR724X_PCI_REG_INT_MASK); __raw_writel(t | AR724X_PCI_INT_DEV0, base + AR724X_PCI_REG_INT_MASK); @@ -232,13 +288,17 @@ static void ar724x_pci_irq_unmask(struct irq_data *d) static void ar724x_pci_irq_mask(struct irq_data *d) { + struct ar724x_pci_controller *apc; void __iomem *base; + int offset; u32 t; - base = ar724x_pci_ctrl_base; + apc = irq_data_get_irq_chip_data(d); + base = apc->ctrl_base; + offset = apc->irq_base - d->irq; - switch (d->irq) { - case ATH79_PCI_IRQ(0): + switch (offset) { + case 0: t = __raw_readl(base + AR724X_PCI_REG_INT_MASK); __raw_writel(t & ~AR724X_PCI_INT_DEV0, base + AR724X_PCI_REG_INT_MASK); @@ -262,53 +322,123 @@ static struct irq_chip ar724x_pci_irq_chip = { .irq_mask_ack = ar724x_pci_irq_mask, }; -static void __init ar724x_pci_irq_init(int irq) +static void ar724x_pci_irq_init(struct ar724x_pci_controller *apc, + int id) { void __iomem *base; int i; - base = ar724x_pci_ctrl_base; + base = apc->ctrl_base; __raw_writel(0, base + AR724X_PCI_REG_INT_MASK); __raw_writel(0, base + AR724X_PCI_REG_INT_STATUS); - BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR724X_PCI_IRQ_COUNT); + apc->irq_base = ATH79_PCI_IRQ_BASE + (id * AR724X_PCI_IRQ_COUNT); - for (i = ATH79_PCI_IRQ_BASE; - i < ATH79_PCI_IRQ_BASE + AR724X_PCI_IRQ_COUNT; i++) + for (i = apc->irq_base; + i < apc->irq_base + AR724X_PCI_IRQ_COUNT; i++) { irq_set_chip_and_handler(i, &ar724x_pci_irq_chip, handle_level_irq); + irq_set_chip_data(i, apc); + } - irq_set_chained_handler(irq, ar724x_pci_irq_handler); + irq_set_handler_data(apc->irq, apc); + irq_set_chained_handler(apc->irq, ar724x_pci_irq_handler); } -int __init ar724x_pcibios_init(int irq) +static int ar724x_pci_probe(struct platform_device *pdev) { - int ret; + struct ar724x_pci_controller *apc; + struct resource *res; + int id; - ret = -ENOMEM; + id = pdev->id; + if (id == -1) + id = 0; - ar724x_pci_devcfg_base = ioremap(AR724X_PCI_CFG_BASE, - AR724X_PCI_CFG_SIZE); - if (ar724x_pci_devcfg_base == NULL) - goto err; + apc = devm_kzalloc(&pdev->dev, sizeof(struct ar724x_pci_controller), + GFP_KERNEL); + if (!apc) + return -ENOMEM; - ar724x_pci_ctrl_base = ioremap(AR724X_PCI_CTRL_BASE, - AR724X_PCI_CTRL_SIZE); - if (ar724x_pci_ctrl_base == NULL) - goto err_unmap_devcfg; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl_base"); + if (!res) + return -EINVAL; - ar724x_pci_link_up = ar724x_pci_check_link(); - if (!ar724x_pci_link_up) - pr_warn("ar724x: PCIe link is down\n"); + apc->ctrl_base = devm_request_and_ioremap(&pdev->dev, res); + if (apc->ctrl_base == NULL) + return -EBUSY; - ar724x_pci_irq_init(irq); - register_pci_controller(&ar724x_pci_controller); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_base"); + if (!res) + return -EINVAL; - return PCIBIOS_SUCCESSFUL; + apc->devcfg_base = devm_request_and_ioremap(&pdev->dev, res); + if (!apc->devcfg_base) + return -EBUSY; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "crp_base"); + if (!res) + return -EINVAL; -err_unmap_devcfg: - iounmap(ar724x_pci_devcfg_base); -err: - return ret; + apc->crp_base = devm_request_and_ioremap(&pdev->dev, res); + if (apc->crp_base == NULL) + return -EBUSY; + + apc->irq = platform_get_irq(pdev, 0); + if (apc->irq < 0) + return -EINVAL; + + spin_lock_init(&apc->lock); + + res = platform_get_resource_byname(pdev, IORESOURCE_IO, "io_base"); + if (!res) + return -EINVAL; + + apc->io_res.parent = res; + apc->io_res.name = "PCI IO space"; + apc->io_res.start = res->start; + apc->io_res.end = res->end; + apc->io_res.flags = IORESOURCE_IO; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem_base"); + if (!res) + return -EINVAL; + + apc->mem_res.parent = res; + apc->mem_res.name = "PCI memory space"; + apc->mem_res.start = res->start; + apc->mem_res.end = res->end; + apc->mem_res.flags = IORESOURCE_MEM; + + apc->pci_controller.pci_ops = &ar724x_pci_ops; + apc->pci_controller.io_resource = &apc->io_res; + apc->pci_controller.mem_resource = &apc->mem_res; + + apc->link_up = ar724x_pci_check_link(apc); + if (!apc->link_up) + dev_warn(&pdev->dev, "PCIe link is down\n"); + + ar724x_pci_irq_init(apc, id); + + ar724x_pci_local_write(apc, PCI_COMMAND, 4, AR724X_PCI_CMD_INIT); + + register_pci_controller(&apc->pci_controller); + + return 0; } + +static struct platform_driver ar724x_pci_driver = { + .probe = ar724x_pci_probe, + .driver = { + .name = "ar724x-pci", + .owner = THIS_MODULE, + }, +}; + +static int __init ar724x_pci_init(void) +{ + return platform_driver_register(&ar724x_pci_driver); +} + +postcore_initcall(ar724x_pci_init); diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c index 95681789b51e..f32664bbbe17 100644 --- a/arch/mips/pci/pci-lantiq.c +++ b/arch/mips/pci/pci-lantiq.c @@ -129,8 +129,16 @@ static int ltq_pci_startup(struct platform_device *pdev) /* setup reset gpio used by pci */ reset_gpio = of_get_named_gpio(node, "gpio-reset", 0); - if (gpio_is_valid(reset_gpio)) - devm_gpio_request(&pdev->dev, reset_gpio, "pci-reset"); + if (gpio_is_valid(reset_gpio)) { + int ret = devm_gpio_request(&pdev->dev, + reset_gpio, "pci-reset"); + if (ret) { + dev_err(&pdev->dev, + "failed to request gpio %d\n", reset_gpio); + return ret; + } + gpio_direction_output(reset_gpio, 1); + } /* enable auto-switching between PCI and EBU */ ltq_pci_w32(0xa, PCI_CR_CLK_CTRL); diff --git a/arch/mips/pci/pci-xlp.c b/arch/mips/pci/pci-xlp.c index ad55f2cfeec1..653d2db9e0c5 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> @@ -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; } @@ -157,32 +162,38 @@ struct pci_controller nlm_pci_controller = { .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,42 +202,48 @@ 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); @@ -235,7 +252,26 @@ static int __init pcibios_init(void) 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; diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index e8a14a6514cf..0872f12f268d 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -175,9 +175,20 @@ static DEFINE_MUTEX(pci_scan_mutex); void register_pci_controller(struct pci_controller *hose) { - if (request_resource(&iomem_resource, hose->mem_resource) < 0) + struct resource *parent; + + parent = hose->mem_resource->parent; + if (!parent) + parent = &iomem_resource; + + if (request_resource(parent, hose->mem_resource) < 0) goto out; - if (request_resource(&ioport_resource, hose->io_resource) < 0) { + + parent = hose->io_resource->parent; + if (!parent) + parent = &ioport_resource; + + if (request_resource(parent, hose->io_resource) < 0) { release_resource(hose->mem_resource); goto out; } |