Commit 4c07c7df authored by Gabor Juhos's avatar Gabor Juhos Committed by Ralf Baechle

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: default avatarGabor Juhos <juhosg@openwrt.org>
Cc:  linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/3496/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 93ef85b5
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/mach-ath79/ath79.h> #include <asm/mach-ath79/ath79.h>
#include <asm/mach-ath79/irq.h>
#include <asm/mach-ath79/pci.h> #include <asm/mach-ath79/pci.h>
#include "pci.h" #include "pci.h"
...@@ -50,7 +51,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev) ...@@ -50,7 +51,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
int __init ath79_register_pci(void) int __init ath79_register_pci(void)
{ {
if (soc_is_ar724x()) if (soc_is_ar724x())
return ar724x_pcibios_init(); return ar724x_pcibios_init(ATH79_CPU_IRQ_IP2);
return -ENODEV; return -ENODEV;
} }
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
#define __ASM_MACH_ATH79_PCI_H #define __ASM_MACH_ATH79_PCI_H
#if defined(CONFIG_PCI) && defined(CONFIG_SOC_AR724X) #if defined(CONFIG_PCI) && defined(CONFIG_SOC_AR724X)
int ar724x_pcibios_init(void); int ar724x_pcibios_init(int irq);
#else #else
static inline int ar724x_pcibios_init(void) { return 0; } static inline int ar724x_pcibios_init(int irq) { return 0; }
#endif #endif
#endif /* __ASM_MACH_ATH79_PCI_H */ #endif /* __ASM_MACH_ATH79_PCI_H */
...@@ -8,19 +8,32 @@ ...@@ -8,19 +8,32 @@
* by the Free Software Foundation. * by the Free Software Foundation.
*/ */
#include <linux/irq.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/mach-ath79/ath79.h> #include <asm/mach-ath79/ath79.h>
#include <asm/mach-ath79/ar71xx_regs.h>
#include <asm/mach-ath79/pci.h> #include <asm/mach-ath79/pci.h>
#define AR724X_PCI_CFG_BASE 0x14000000 #define AR724X_PCI_CFG_BASE 0x14000000
#define AR724X_PCI_CFG_SIZE 0x1000 #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_BASE 0x10000000
#define AR724X_PCI_MEM_SIZE 0x08000000 #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 #define AR7240_BAR0_WAR_VALUE 0xffff
static DEFINE_SPINLOCK(ar724x_pci_lock); static DEFINE_SPINLOCK(ar724x_pci_lock);
static void __iomem *ar724x_pci_devcfg_base; static void __iomem *ar724x_pci_devcfg_base;
static void __iomem *ar724x_pci_ctrl_base;
static u32 ar724x_pci_bar0_value; static u32 ar724x_pci_bar0_value;
static bool ar724x_pci_bar0_is_cached; static bool ar724x_pci_bar0_is_cached;
...@@ -164,14 +177,115 @@ static struct pci_controller ar724x_pci_controller = { ...@@ -164,14 +177,115 @@ static struct pci_controller ar724x_pci_controller = {
.mem_resource = &ar724x_mem_resource, .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_devcfg_base = ioremap(AR724X_PCI_CFG_BASE,
AR724X_PCI_CFG_SIZE); AR724X_PCI_CFG_SIZE);
if (ar724x_pci_devcfg_base == NULL) 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); register_pci_controller(&ar724x_pci_controller);
return PCIBIOS_SUCCESSFUL; return PCIBIOS_SUCCESSFUL;
err_unmap_devcfg:
iounmap(ar724x_pci_devcfg_base);
err:
return ret;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment