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=2ad652f27a03795cc173f2e53f4268f1e08e5e36;hb=c1e8a5560a250f85411438381a27b98af7c9c3d4;hpb=fec65e77938a057caedfffb3d1c70bf885499848 diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/irq.c b/target/linux/ar71xx/files/arch/mips/ar71xx/irq.c index 2ad652f27a..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) 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,12 +23,15 @@ #include +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); @@ -36,22 +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 */ - ar71xx_gpio_rr(GPIO_REG_INT_ENABLE); + (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 */ - ar71xx_gpio_rr(GPIO_REG_INT_ENABLE); + (void) __raw_readl(base + GPIO_REG_INT_ENABLE); } #if 0 @@ -82,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++) { @@ -134,38 +148,65 @@ 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 */ - ar71xx_reset_rr(AR71XX_RESET_REG_MISC_INT_ENABLE); + (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 */ - ar71xx_reset_rr(AR71XX_RESET_REG_MISC_INT_ENABLE); + (void) __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE); } static void ar724x_misc_irq_ack(unsigned int irq) { + void __iomem *base = ar71xx_reset_base; + u32 t; + irq -= AR71XX_MISC_IRQ_BASE; - ar71xx_reset_wr(AR71XX_RESET_REG_MISC_INT_STATUS, - ar71xx_reset_rr(AR71XX_RESET_REG_MISC_INT_STATUS) & ~(1 << irq)); + + t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); + __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_STATUS); /* flush write */ - ar71xx_reset_rr(AR71XX_RESET_REG_MISC_INT_STATUS); + (void) __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS); } static struct irq_chip ar71xx_misc_irq_chip = { @@ -181,15 +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); - if (ar71xx_soc == AR71XX_SOC_AR7240) + 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; - else + 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++) { @@ -210,8 +261,17 @@ asmlinkage void plat_irq_dispatch(void) if (pending & STATUSF_IP7) do_IRQ(AR71XX_CPU_IRQ_TIMER); - else if (pending & STATUSF_IP2) + 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); @@ -231,6 +291,27 @@ 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();