214 lines
5.5 KiB
Diff
214 lines
5.5 KiB
Diff
From 1fd24b552708544ca6233ff7ba60342e9f7e5582 Mon Sep 17 00:00:00 2001
|
|
From: Gabor Juhos <juhosg@openwrt.org>
|
|
Date: Wed, 14 Mar 2012 10:36:07 +0100
|
|
Subject: [PATCH 16/47] 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>
|
|
Cc: linux-mips@linux-mips.org
|
|
Patchwork: https://patchwork.linux-mips.org/patch/3496/
|
|
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
|
|
---
|
|
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;
|
|
}
|