X-Git-Url: http://git.openwrt.org/?p=openwrt%2Fsvn-archive%2Farchive.git;a=blobdiff_plain;f=target%2Flinux%2Far71xx%2Ffiles%2Farch%2Fmips%2Far71xx%2Firq.c;h=12919f7e588a36f4a353c2d5d22174b4efa7f6d9;hp=eda74744183239da1651c65f8f54ed3b86575cc2;hb=c1e8a5560a250f85411438381a27b98af7c9c3d4;hpb=0992cec37834d7c45f5727ff294cb12dbf6ab1f3 diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/irq.c b/target/linux/ar71xx/files/arch/mips/ar71xx/irq.c index eda7474418..12919f7e58 100644 --- a/target/linux/ar71xx/files/arch/mips/ar71xx/irq.c +++ b/target/linux/ar71xx/files/arch/mips/ar71xx/irq.c @@ -1,10 +1,12 @@ /* * Atheros AR71xx SoC specific interrupt handling * - * Copyright (C) 2008 Gabor Juhos + * Copyright (C) 2010-2011 Jaiganesh Narayanan + * Copyright (C) 2008-2010 Gabor Juhos * Copyright (C) 2008 Imre Kaloz * - * Parts of this file are based on Atheros' 2.6.15 BSP + * Parts of this file are based on Atheros 2.6.15 BSP + * Parts of this file are based on Atheros 2.6.31 BSP * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -21,78 +23,15 @@ #include -#ifdef CONFIG_PCI -static void ar71xx_pci_irq_dispatch(void) -{ - u32 pending; - - pending = ar71xx_reset_rr(AR71XX_RESET_REG_PCI_INT_STATUS) & - ar71xx_reset_rr(AR71XX_RESET_REG_PCI_INT_ENABLE); - - if (pending & PCI_INT_DEV0) - do_IRQ(AR71XX_PCI_IRQ_DEV0); - - else if (pending & PCI_INT_DEV1) - do_IRQ(AR71XX_PCI_IRQ_DEV1); - - else if (pending & PCI_INT_DEV2) - do_IRQ(AR71XX_PCI_IRQ_DEV2); - - else - spurious_interrupt(); -} - -static void ar71xx_pci_irq_unmask(unsigned int irq) -{ - irq -= AR71XX_PCI_IRQ_BASE; - ar71xx_reset_wr(AR71XX_RESET_REG_PCI_INT_ENABLE, - ar71xx_reset_rr(AR71XX_RESET_REG_PCI_INT_ENABLE) | (1 << irq)); -} - -static void ar71xx_pci_irq_mask(unsigned int irq) -{ - irq -= AR71XX_PCI_IRQ_BASE; - ar71xx_reset_wr(AR71XX_RESET_REG_PCI_INT_ENABLE, - ar71xx_reset_rr(AR71XX_RESET_REG_PCI_INT_ENABLE) & ~(1 << irq)); -} - -static struct irq_chip ar71xx_pci_irq_chip = { - .name = "AR71XX PCI ", - .mask = ar71xx_pci_irq_mask, - .unmask = ar71xx_pci_irq_unmask, - .mask_ack = ar71xx_pci_irq_mask, -}; - -static struct irqaction ar71xx_pci_irqaction = { - .handler = no_action, - .name = "cascade [AR71XX PCI]", -}; - -static void __init ar71xx_pci_irq_init(void) -{ - int i; - - ar71xx_reset_wr(AR71XX_RESET_REG_PCI_INT_ENABLE, 0); - ar71xx_reset_wr(AR71XX_RESET_REG_PCI_INT_STATUS, 0); - - for (i = AR71XX_PCI_IRQ_BASE; - i < AR71XX_PCI_IRQ_BASE + AR71XX_PCI_IRQ_COUNT; i++) { - irq_desc[i].status = IRQ_DISABLED; - set_irq_chip_and_handler(i, &ar71xx_pci_irq_chip, - handle_level_irq); - } - - setup_irq(AR71XX_CPU_IRQ_PCI, &ar71xx_pci_irqaction); -} - -#endif /* CONFIG_PCI */ +static int ip2_flush_reg; static void ar71xx_gpio_irq_dispatch(void) { + void __iomem *base = ar71xx_gpio_base; u32 pending; - pending = ar71xx_gpio_rr(GPIO_REG_INT_PENDING) - & ar71xx_gpio_rr(GPIO_REG_INT_ENABLE); + pending = __raw_readl(base + GPIO_REG_INT_PENDING) & + __raw_readl(base + GPIO_REG_INT_ENABLE); if (pending) do_IRQ(AR71XX_GPIO_IRQ_BASE + fls(pending) - 1); @@ -102,16 +41,30 @@ static void ar71xx_gpio_irq_dispatch(void) static void ar71xx_gpio_irq_unmask(unsigned int irq) { + void __iomem *base = ar71xx_gpio_base; + u32 t; + irq -= AR71XX_GPIO_IRQ_BASE; - ar71xx_gpio_wr(GPIO_REG_INT_ENABLE, - ar71xx_gpio_rr(GPIO_REG_INT_ENABLE) | (1 << irq)); + + t = __raw_readl(base + GPIO_REG_INT_ENABLE); + __raw_writel(t | (1 << irq), base + GPIO_REG_INT_ENABLE); + + /* flush write */ + (void) __raw_readl(base + GPIO_REG_INT_ENABLE); } static void ar71xx_gpio_irq_mask(unsigned int irq) { + void __iomem *base = ar71xx_gpio_base; + u32 t; + irq -= AR71XX_GPIO_IRQ_BASE; - ar71xx_gpio_wr(GPIO_REG_INT_ENABLE, - ar71xx_gpio_rr(GPIO_REG_INT_ENABLE) & ~(1 << irq)); + + t = __raw_readl(base + GPIO_REG_INT_ENABLE); + __raw_writel(t & ~(1 << irq), base + GPIO_REG_INT_ENABLE); + + /* flush write */ + (void) __raw_readl(base + GPIO_REG_INT_ENABLE); } #if 0 @@ -124,7 +77,7 @@ static int ar71xx_gpio_irq_set_type(unsigned int irq, unsigned int flow_type) #define ar71xx_gpio_irq_set_type NULL #endif -struct irq_chip ar71xx_gpio_irq_chip = { +static struct irq_chip ar71xx_gpio_irq_chip = { .name = "AR71XX GPIO", .unmask = ar71xx_gpio_irq_unmask, .mask = ar71xx_gpio_irq_mask, @@ -142,16 +95,17 @@ static struct irqaction ar71xx_gpio_irqaction = { static void __init ar71xx_gpio_irq_init(void) { + void __iomem *base = ar71xx_gpio_base; int i; - ar71xx_gpio_wr(GPIO_REG_INT_ENABLE, 0); - ar71xx_gpio_wr(GPIO_REG_INT_PENDING, 0); + __raw_writel(0, base + GPIO_REG_INT_ENABLE); + __raw_writel(0, base + GPIO_REG_INT_PENDING); /* setup type of all GPIO interrupts to level sensitive */ - ar71xx_gpio_wr(GPIO_REG_INT_TYPE, GPIO_INT_ALL); + __raw_writel(GPIO_INT_ALL, base + GPIO_REG_INT_TYPE); /* setup polarity of all GPIO interrupts to active high */ - ar71xx_gpio_wr(GPIO_REG_INT_POLARITY, GPIO_INT_ALL); + __raw_writel(GPIO_INT_ALL, base + GPIO_REG_INT_POLARITY); for (i = AR71XX_GPIO_IRQ_BASE; i < AR71XX_GPIO_IRQ_BASE + AR71XX_GPIO_IRQ_COUNT; i++) { @@ -194,29 +148,71 @@ static void ar71xx_misc_irq_dispatch(void) else if (pending & MISC_INT_WDOG) do_IRQ(AR71XX_MISC_IRQ_WDOG); + else if (pending & MISC_INT_TIMER2) + do_IRQ(AR71XX_MISC_IRQ_TIMER2); + + else if (pending & MISC_INT_TIMER3) + do_IRQ(AR71XX_MISC_IRQ_TIMER3); + + else if (pending & MISC_INT_TIMER4) + do_IRQ(AR71XX_MISC_IRQ_TIMER4); + + else if (pending & MISC_INT_DDR_PERF) + do_IRQ(AR71XX_MISC_IRQ_DDR_PERF); + + else if (pending & MISC_INT_ENET_LINK) + do_IRQ(AR71XX_MISC_IRQ_ENET_LINK); + else spurious_interrupt(); } static void ar71xx_misc_irq_unmask(unsigned int irq) { + void __iomem *base = ar71xx_reset_base; + u32 t; + irq -= AR71XX_MISC_IRQ_BASE; - ar71xx_reset_wr(AR71XX_RESET_REG_MISC_INT_ENABLE, - ar71xx_reset_rr(AR71XX_RESET_REG_MISC_INT_ENABLE) | (1 << irq)); + + t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); + __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); + + /* flush write */ + (void) __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); } static void ar71xx_misc_irq_mask(unsigned int irq) { + void __iomem *base = ar71xx_reset_base; + u32 t; + irq -= AR71XX_MISC_IRQ_BASE; - ar71xx_reset_wr(AR71XX_RESET_REG_MISC_INT_ENABLE, - ar71xx_reset_rr(AR71XX_RESET_REG_MISC_INT_ENABLE) & ~(1 << irq)); + + t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); + __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE); + + /* flush write */ + (void) __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); } -struct irq_chip ar71xx_misc_irq_chip = { +static void ar724x_misc_irq_ack(unsigned int irq) +{ + void __iomem *base = ar71xx_reset_base; + u32 t; + + irq -= AR71XX_MISC_IRQ_BASE; + + t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); + __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_STATUS); + + /* flush write */ + (void) __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); +} + +static struct irq_chip ar71xx_misc_irq_chip = { .name = "AR71XX MISC", .unmask = ar71xx_misc_irq_unmask, .mask = ar71xx_misc_irq_mask, - .mask_ack = ar71xx_misc_irq_mask, }; static struct irqaction ar71xx_misc_irqaction = { @@ -226,10 +222,25 @@ static struct irqaction ar71xx_misc_irqaction = { static void __init ar71xx_misc_irq_init(void) { + void __iomem *base = ar71xx_reset_base; int i; - ar71xx_reset_wr(AR71XX_RESET_REG_MISC_INT_ENABLE, 0); - ar71xx_reset_wr(AR71XX_RESET_REG_MISC_INT_STATUS, 0); + __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE); + __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS); + + switch (ar71xx_soc) { + case AR71XX_SOC_AR7240: + case AR71XX_SOC_AR7241: + case AR71XX_SOC_AR7242: + case AR71XX_SOC_AR9341: + case AR71XX_SOC_AR9342: + case AR71XX_SOC_AR9344: + ar71xx_misc_irq_chip.ack = ar724x_misc_irq_ack; + break; + default: + ar71xx_misc_irq_chip.mask_ack = ar71xx_misc_irq_mask; + break; + } for (i = AR71XX_MISC_IRQ_BASE; i < AR71XX_MISC_IRQ_BASE + AR71XX_MISC_IRQ_COUNT; i++) { @@ -250,10 +261,17 @@ asmlinkage void plat_irq_dispatch(void) if (pending & STATUSF_IP7) do_IRQ(AR71XX_CPU_IRQ_TIMER); -#ifdef CONFIG_PCI - else if (pending & STATUSF_IP2) - ar71xx_pci_irq_dispatch(); -#endif + else if (pending & STATUSF_IP2) { + /* + * This IRQ is meant for a PCI device. Drivers for PCI devices + * typically allocate coherent DMA memory for the descriptor + * ring, however the DMA controller may still have some + * unsynchronized data in the FIFO. + * Issue a flush here to ensure that the driver sees the update. + */ + ar71xx_ddr_flush(ip2_flush_reg); + do_IRQ(AR71XX_CPU_IRQ_IP2); + } else if (pending & STATUSF_IP4) do_IRQ(AR71XX_CPU_IRQ_GE0); @@ -273,13 +291,32 @@ asmlinkage void plat_irq_dispatch(void) void __init arch_init_irq(void) { + switch (ar71xx_soc) { + case AR71XX_SOC_AR7240: + case AR71XX_SOC_AR7241: + case AR71XX_SOC_AR7242: + ip2_flush_reg = AR724X_DDR_REG_FLUSH_PCIE; + break; + case AR71XX_SOC_AR9130: + case AR71XX_SOC_AR9132: + ip2_flush_reg = AR91XX_DDR_REG_FLUSH_WMAC; + break; + case AR71XX_SOC_AR9341: + case AR71XX_SOC_AR9342: + case AR71XX_SOC_AR9344: + ip2_flush_reg = AR934X_DDR_REG_FLUSH_PCIE; + break; + + default: + ip2_flush_reg = AR71XX_DDR_REG_FLUSH_PCI; + break; + } + mips_cpu_irq_init(); ar71xx_misc_irq_init(); -#ifdef CONFIG_PCI - ar71xx_pci_irq_init(); -#endif + cp0_perfcount_irq = AR71XX_MISC_IRQ_PERFC; ar71xx_gpio_irq_init(); }