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

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
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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 *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;
}
+2 −2
Original line number Diff line number Diff line
@@ -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 */
+116 −2
Original line number Diff line number Diff line
@@ -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_controller = {
	.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;
}