diff options
Diffstat (limited to 'target/linux/ar71xx/patches-3.2/113-MIPS-ath79-add-PCI-IRQ-handling-code-for-AR724X-SoCs.patch')
-rw-r--r-- | target/linux/ar71xx/patches-3.2/113-MIPS-ath79-add-PCI-IRQ-handling-code-for-AR724X-SoCs.patch | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/target/linux/ar71xx/patches-3.2/113-MIPS-ath79-add-PCI-IRQ-handling-code-for-AR724X-SoCs.patch b/target/linux/ar71xx/patches-3.2/113-MIPS-ath79-add-PCI-IRQ-handling-code-for-AR724X-SoCs.patch new file mode 100644 index 0000000..6da2df4 --- /dev/null +++ b/target/linux/ar71xx/patches-3.2/113-MIPS-ath79-add-PCI-IRQ-handling-code-for-AR724X-SoCs.patch @@ -0,0 +1,213 @@ +From a4fbc2dec67a5d760e25e3c3a6c392191a5405c6 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Tue, 22 Nov 2011 14:11:19 +0100 +Subject: [PATCH 13/35] MIPS: ath79: add PCI IRQ handling code for AR724X SoCs + +The PCI Host Controller of the AR724x SoC has a +built-in IRQ controller. The current code does +not supports that, so the IRQ lines wired to this +controller are not usable. This leads to failed +'request_irq' calls: + + ath9k 0000:00:00.0: request_irq failed + ath9k: probe of 0000:00:00.0 failed with error -89 + +This patch adds support for the IRQ controller +in order to make PCI IRQs work. + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> + +v2: - move the interrupt controller related defines from + the workaround patch +--- + arch/mips/ath79/pci.c | 3 +- + arch/mips/include/asm/mach-ath79/pci.h | 4 +- + arch/mips/pci/pci-ar724x.c | 118 +++++++++++++++++++++++++++++++- + 3 files changed, 120 insertions(+), 5 deletions(-) + +--- a/arch/mips/ath79/pci.c ++++ b/arch/mips/ath79/pci.c +@@ -10,6 +10,7 @@ + + #include <linux/pci.h> + #include <asm/mach-ath79/ath79.h> ++#include <asm/mach-ath79/irq.h> + #include <asm/mach-ath79/pci.h> + #include "pci.h" + +@@ -50,7 +51,7 @@ int pcibios_plat_dev_init(struct pci_dev + int __init ath79_register_pci(void) + { + if (soc_is_ar724x()) +- return ar724x_pcibios_init(); ++ return ar724x_pcibios_init(ATH79_CPU_IRQ_IP2); + + return -ENODEV; + } +--- a/arch/mips/include/asm/mach-ath79/pci.h ++++ b/arch/mips/include/asm/mach-ath79/pci.h +@@ -12,9 +12,9 @@ + #define __ASM_MACH_ATH79_PCI_H + + #if defined(CONFIG_PCI) && defined(CONFIG_SOC_AR724X) +-int ar724x_pcibios_init(void); ++int ar724x_pcibios_init(int irq); + #else +-static inline int ar724x_pcibios_init(void) { return 0 }; ++static inline int ar724x_pcibios_init(int irq) { return 0 }; + #endif + + #endif /* __ASM_MACH_ATH79_PCI_H */ +--- a/arch/mips/pci/pci-ar724x.c ++++ b/arch/mips/pci/pci-ar724x.c +@@ -8,19 +8,32 @@ + * by the Free Software Foundation. + */ + ++#include <linux/irq.h> + #include <linux/pci.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 0x08000000 + ++#define AR724X_PCI_REG_INT_STATUS 0x4c ++#define AR724X_PCI_REG_INT_MASK 0x50 ++ ++#define AR724X_PCI_INT_DEV0 BIT(14) ++ ++#define AR724X_PCI_IRQ_COUNT 1 ++ + #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; + + static u32 ar724x_pci_bar0_value; + static bool ar724x_pci_bar0_is_cached; +@@ -164,14 +177,115 @@ static struct pci_controller ar724x_pci_ + .mem_resource = &ar724x_mem_resource, + }; + +-int __init ar724x_pcibios_init(void) ++static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc) ++{ ++ void __iomem *base; ++ u32 pending; ++ ++ base = ar724x_pci_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)); ++ ++ else ++ spurious_interrupt(); ++} ++ ++static void ar724x_pci_irq_unmask(struct irq_data *d) ++{ ++ void __iomem *base; ++ u32 t; ++ ++ base = ar724x_pci_ctrl_base; ++ ++ switch (d->irq) { ++ case ATH79_PCI_IRQ(0): ++ t = __raw_readl(base + AR724X_PCI_REG_INT_MASK); ++ __raw_writel(t | AR724X_PCI_INT_DEV0, ++ base + AR724X_PCI_REG_INT_MASK); ++ /* flush write */ ++ __raw_readl(base + AR724X_PCI_REG_INT_MASK); ++ } ++} ++ ++static void ar724x_pci_irq_mask(struct irq_data *d) ++{ ++ void __iomem *base; ++ u32 t; ++ ++ base = ar724x_pci_ctrl_base; ++ ++ switch (d->irq) { ++ case ATH79_PCI_IRQ(0): ++ t = __raw_readl(base + AR724X_PCI_REG_INT_MASK); ++ __raw_writel(t & ~AR724X_PCI_INT_DEV0, ++ base + AR724X_PCI_REG_INT_MASK); ++ ++ /* flush write */ ++ __raw_readl(base + AR724X_PCI_REG_INT_MASK); ++ ++ t = __raw_readl(base + AR724X_PCI_REG_INT_STATUS); ++ __raw_writel(t | AR724X_PCI_INT_DEV0, ++ base + AR724X_PCI_REG_INT_STATUS); ++ ++ /* flush write */ ++ __raw_readl(base + AR724X_PCI_REG_INT_STATUS); ++ } ++} ++ ++static struct irq_chip ar724x_pci_irq_chip = { ++ .name = "AR724X PCI ", ++ .irq_mask = ar724x_pci_irq_mask, ++ .irq_unmask = ar724x_pci_irq_unmask, ++ .irq_mask_ack = ar724x_pci_irq_mask, ++}; ++ ++static void __init ar724x_pci_irq_init(int irq) ++{ ++ void __iomem *base; ++ int i; ++ ++ base = ar724x_pci_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); ++ ++ for (i = ATH79_PCI_IRQ_BASE; ++ i < ATH79_PCI_IRQ_BASE + AR724X_PCI_IRQ_COUNT; i++) ++ irq_set_chip_and_handler(i, &ar724x_pci_irq_chip, ++ handle_level_irq); ++ ++ irq_set_chained_handler(irq, ar724x_pci_irq_handler); ++} ++ ++int __init ar724x_pcibios_init(int irq) + { ++ int ret; ++ ++ ret = -ENOMEM; ++ + ar724x_pci_devcfg_base = ioremap(AR724X_PCI_CFG_BASE, + AR724X_PCI_CFG_SIZE); + if (ar724x_pci_devcfg_base == NULL) +- return -ENOMEM; ++ goto err; + ++ ar724x_pci_ctrl_base = ioremap(AR724X_PCI_CTRL_BASE, ++ AR724X_PCI_CTRL_SIZE); ++ if (ar724x_pci_ctrl_base == NULL) ++ goto err_unmap_devcfg; ++ ++ ar724x_pci_irq_init(irq); + register_pci_controller(&ar724x_pci_controller); + + return PCIBIOS_SUCCESSFUL; ++ ++err_unmap_devcfg: ++ iounmap(ar724x_pci_devcfg_base); ++err: ++ return ret; + } |