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=7165ca97db20b214e929e44342b9739a2b2ee6be;hp=a912f3892090cc5fbba40f791239492c7ef29086;hb=da0455c67582bddd9936d1b92db1d84d1431c8db;hpb=658f03a76b5065f571879a1dde0269cfeb67c66a diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/irq.c b/target/linux/ar71xx/files/arch/mips/ar71xx/irq.c index a912f38920..7165ca97db 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-2009 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,161 +23,13 @@ #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 if (pending & PCI_INT_CORE) - do_IRQ(AR71XX_PCI_IRQ_CORE); - - 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)); - - /* flush write */ - ar71xx_reset_rr(AR71XX_RESET_REG_PCI_INT_ENABLE); -} - -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)); - - /* flush write */ - ar71xx_reset_rr(AR71XX_RESET_REG_PCI_INT_ENABLE); -} - -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); -} - -static void ar724x_pci_irq_dispatch(void) -{ - u32 pending; - - pending = ar724x_pci_rr(AR724X_PCI_REG_INT_STATUS) & - ar724x_pci_rr(AR724X_PCI_REG_INT_MASK); - - if (pending & AR724X_PCI_INT_DEV0) - do_IRQ(AR71XX_PCI_IRQ_DEV0); - - else - spurious_interrupt(); -} - -static void ar724x_pci_irq_unmask(unsigned int irq) -{ - switch (irq) { - case AR71XX_PCI_IRQ_DEV0: - irq -= AR71XX_PCI_IRQ_BASE; - ar724x_pci_wr(AR724X_PCI_REG_INT_MASK, - ar724x_pci_rr(AR724X_PCI_REG_INT_MASK) | - AR724X_PCI_INT_DEV0); - /* flush write */ - ar724x_pci_rr(AR724X_PCI_REG_INT_MASK); - } -} - -static void ar724x_pci_irq_mask(unsigned int irq) -{ - switch (irq) { - case AR71XX_PCI_IRQ_DEV0: - irq -= AR71XX_PCI_IRQ_BASE; - ar724x_pci_wr(AR724X_PCI_REG_INT_MASK, - ar724x_pci_rr(AR724X_PCI_REG_INT_MASK) & - ~AR724X_PCI_INT_DEV0); - /* flush write */ - ar724x_pci_rr(AR724X_PCI_REG_INT_MASK); - - ar724x_pci_wr(AR724X_PCI_REG_INT_STATUS, - ar724x_pci_rr(AR724X_PCI_REG_INT_STATUS) | - AR724X_PCI_INT_DEV0); - /* flush write */ - ar724x_pci_rr(AR724X_PCI_REG_INT_STATUS); - } -} - -static struct irq_chip ar724x_pci_irq_chip = { - .name = "AR724X PCI ", - .mask = ar724x_pci_irq_mask, - .unmask = ar724x_pci_irq_unmask, - .mask_ack = ar724x_pci_irq_mask, -}; - -static struct irqaction ar724x_pci_irqaction = { - .handler = no_action, - .name = "cascade [AR724X PCI]", -}; - -static void __init ar724x_pci_irq_init(void) -{ - int i; - - ar724x_pci_wr(AR724X_PCI_REG_INT_MASK, 0); - ar724x_pci_wr(AR724X_PCI_REG_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, &ar724x_pci_irq_chip, - handle_level_irq); - } - - setup_irq(AR71XX_CPU_IRQ_PCI, &ar724x_pci_irqaction); -} -#endif /* CONFIG_PCI */ - 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); @@ -183,42 +37,37 @@ static void ar71xx_gpio_irq_dispatch(void) spurious_interrupt(); } -static void ar71xx_gpio_irq_unmask(unsigned int irq) +static void ar71xx_gpio_irq_unmask(struct irq_data *d) { - irq -= AR71XX_GPIO_IRQ_BASE; - ar71xx_gpio_wr(GPIO_REG_INT_ENABLE, - ar71xx_gpio_rr(GPIO_REG_INT_ENABLE) | (1 << irq)); + unsigned int irq = d->irq - AR71XX_GPIO_IRQ_BASE; + void __iomem *base = ar71xx_gpio_base; + u32 t; + + 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) +static void ar71xx_gpio_irq_mask(struct irq_data *d) { - irq -= AR71XX_GPIO_IRQ_BASE; - ar71xx_gpio_wr(GPIO_REG_INT_ENABLE, - ar71xx_gpio_rr(GPIO_REG_INT_ENABLE) & ~(1 << irq)); + unsigned int irq = d->irq - AR71XX_GPIO_IRQ_BASE; + void __iomem *base = ar71xx_gpio_base; + u32 t; - /* flush write */ - ar71xx_gpio_rr(GPIO_REG_INT_ENABLE); -} + t = __raw_readl(base + GPIO_REG_INT_ENABLE); + __raw_writel(t & ~(1 << irq), base + GPIO_REG_INT_ENABLE); -#if 0 -static int ar71xx_gpio_irq_set_type(unsigned int irq, unsigned int flow_type) -{ - /* TODO: implement */ - return 0; + /* flush write */ + (void) __raw_readl(base + GPIO_REG_INT_ENABLE); } -#else -#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, - .mask_ack = ar71xx_gpio_irq_mask, - .set_type = ar71xx_gpio_irq_set_type, + .irq_unmask = ar71xx_gpio_irq_unmask, + .irq_mask = ar71xx_gpio_irq_mask, + .irq_mask_ack = ar71xx_gpio_irq_mask, }; static struct irqaction ar71xx_gpio_irqaction = { @@ -226,28 +75,26 @@ static struct irqaction ar71xx_gpio_irqaction = { .name = "cascade [AR71XX GPIO]", }; -#define GPIO_IRQ_INIT_STATUS (IRQ_LEVEL | IRQ_TYPE_LEVEL_HIGH | IRQ_DISABLED) #define GPIO_INT_ALL 0xffff 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++) { - irq_desc[i].status = GPIO_IRQ_INIT_STATUS; - set_irq_chip_and_handler(i, &ar71xx_gpio_irq_chip, + i < AR71XX_GPIO_IRQ_BASE + AR71XX_GPIO_IRQ_COUNT; i++) + irq_set_chip_and_handler(i, &ar71xx_gpio_irq_chip, handle_level_irq); - } setup_irq(AR71XX_MISC_IRQ_GPIO, &ar71xx_gpio_irqaction); } @@ -283,35 +130,68 @@ 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) +static void ar71xx_misc_irq_unmask(struct irq_data *d) { - 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)); + unsigned int irq = d->irq - AR71XX_MISC_IRQ_BASE; + void __iomem *base = ar71xx_reset_base; + u32 t; + + 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) +static void ar71xx_misc_irq_mask(struct irq_data *d) { - 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)); + unsigned int irq = d->irq - AR71XX_MISC_IRQ_BASE; + void __iomem *base = ar71xx_reset_base; + u32 t; + + 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); } -struct irq_chip ar71xx_misc_irq_chip = { +static void ar724x_misc_irq_ack(struct irq_data *d) +{ + unsigned int irq = d->irq - AR71XX_MISC_IRQ_BASE; + void __iomem *base = ar71xx_reset_base; + u32 t; + + 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, + .irq_unmask = ar71xx_misc_irq_unmask, + .irq_mask = ar71xx_misc_irq_mask, }; static struct irqaction ar71xx_misc_irqaction = { @@ -321,27 +201,137 @@ 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_AR9330: + case AR71XX_SOC_AR9331: + case AR71XX_SOC_AR9341: + case AR71XX_SOC_AR9342: + case AR71XX_SOC_AR9344: + ar71xx_misc_irq_chip.irq_ack = ar724x_misc_irq_ack; + break; + default: + ar71xx_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask; + break; + } for (i = AR71XX_MISC_IRQ_BASE; - i < AR71XX_MISC_IRQ_BASE + AR71XX_MISC_IRQ_COUNT; i++) { - irq_desc[i].status = IRQ_DISABLED; - set_irq_chip_and_handler(i, &ar71xx_misc_irq_chip, + i < AR71XX_MISC_IRQ_BASE + AR71XX_MISC_IRQ_COUNT; i++) + irq_set_chip_and_handler(i, &ar71xx_misc_irq_chip, handle_level_irq); - } setup_irq(AR71XX_CPU_IRQ_MISC, &ar71xx_misc_irqaction); } -static void ar913x_wmac_irq_dispatch(void) +static void ar934x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc) +{ + u32 status; + + disable_irq_nosync(irq); + + status = ar71xx_reset_rr(AR934X_RESET_REG_PCIE_WMAC_INT_STATUS); + + if (status & AR934X_PCIE_WMAC_INT_PCIE_ALL) + generic_handle_irq(AR934X_IP2_IRQ_PCIE); + + else if (status & AR934X_PCIE_WMAC_INT_WMAC_ALL) + generic_handle_irq(AR934X_IP2_IRQ_WMAC); + + else + spurious_interrupt(); + + enable_irq(irq); +} + +static void ar934x_ip2_irq_init(void) +{ + int i; + + for (i = AR934X_IP2_IRQ_BASE; + i < AR934X_IP2_IRQ_BASE + AR934X_IP2_IRQ_COUNT; i++) + irq_set_chip_and_handler(i, &dummy_irq_chip, + handle_level_irq); + + irq_set_chained_handler(AR71XX_CPU_IRQ_IP2, ar934x_ip2_irq_dispatch); +} + + +/* + * The IP2/IP3 lines are tied to a PCI/WMAC/USB device. Drivers for + * these devices typically allocate coherent DMA memory, however the + * DMA controller may still have some unsynchronized data in the FIFO. + * Issue a flush in the handlers to ensure that the driver sees + * the update. + */ +static void ar71xx_ip2_handler(void) +{ + ar71xx_ddr_flush(AR71XX_DDR_REG_FLUSH_PCI); + do_IRQ(AR71XX_CPU_IRQ_IP2); +} + +static void ar724x_ip2_handler(void) { - do_IRQ(AR71XX_CPU_IRQ_WMAC); + ar71xx_ddr_flush(AR724X_DDR_REG_FLUSH_PCIE); + do_IRQ(AR71XX_CPU_IRQ_IP2); } -static void (* ar71xx_ip2_irq_handler)(void) = spurious_interrupt; +static void ar913x_ip2_handler(void) +{ + ar71xx_ddr_flush(AR91XX_DDR_REG_FLUSH_WMAC); + do_IRQ(AR71XX_CPU_IRQ_IP2); +} + +static void ar933x_ip2_handler(void) +{ + ar71xx_ddr_flush(AR933X_DDR_REG_FLUSH_WMAC); + do_IRQ(AR71XX_CPU_IRQ_IP2); +} + +static void ar934x_ip2_handler(void) +{ + ar71xx_ddr_flush(AR934X_DDR_REG_FLUSH_PCIE); + do_IRQ(AR71XX_CPU_IRQ_IP2); +} + +static void ar71xx_ip3_handler(void) +{ + ar71xx_ddr_flush(AR71XX_DDR_REG_FLUSH_USB); + do_IRQ(AR71XX_CPU_IRQ_USB); +} + +static void ar724x_ip3_handler(void) +{ + ar71xx_ddr_flush(AR724X_DDR_REG_FLUSH_USB); + do_IRQ(AR71XX_CPU_IRQ_USB); +} + +static void ar913x_ip3_handler(void) +{ + ar71xx_ddr_flush(AR91XX_DDR_REG_FLUSH_USB); + do_IRQ(AR71XX_CPU_IRQ_USB); +} + +static void ar933x_ip3_handler(void) +{ + ar71xx_ddr_flush(AR933X_DDR_REG_FLUSH_USB); + do_IRQ(AR71XX_CPU_IRQ_USB); +} + +static void ar934x_ip3_handler(void) +{ + do_IRQ(AR71XX_CPU_IRQ_USB); +} + +static void (*ip2_handler)(void); +static void (*ip3_handler)(void); asmlinkage void plat_irq_dispatch(void) { @@ -353,7 +343,7 @@ asmlinkage void plat_irq_dispatch(void) do_IRQ(AR71XX_CPU_IRQ_TIMER); else if (pending & STATUSF_IP2) - ar71xx_ip2_irq_handler(); + ip2_handler(); else if (pending & STATUSF_IP4) do_IRQ(AR71XX_CPU_IRQ_GE0); @@ -362,7 +352,7 @@ asmlinkage void plat_irq_dispatch(void) do_IRQ(AR71XX_CPU_IRQ_GE1); else if (pending & STATUSF_IP3) - do_IRQ(AR71XX_CPU_IRQ_USB); + ip3_handler(); else if (pending & STATUSF_IP6) ar71xx_misc_irq_dispatch(); @@ -373,32 +363,54 @@ asmlinkage void plat_irq_dispatch(void) void __init arch_init_irq(void) { - mips_cpu_irq_init(); - - ar71xx_misc_irq_init(); - switch (ar71xx_soc) { case AR71XX_SOC_AR7130: case AR71XX_SOC_AR7141: case AR71XX_SOC_AR7161: -#ifdef CONFIG_PCI - ar71xx_pci_irq_init(); - ar71xx_ip2_irq_handler = ar71xx_pci_irq_dispatch; -#endif + ip2_handler = ar71xx_ip2_handler; + ip3_handler = ar71xx_ip3_handler; break; + case AR71XX_SOC_AR7240: -#ifdef CONFIG_PCI - ar724x_pci_irq_init(); - ar71xx_ip2_irq_handler = ar724x_pci_irq_dispatch; -#endif + case AR71XX_SOC_AR7241: + case AR71XX_SOC_AR7242: + ip2_handler = ar724x_ip2_handler; + ip3_handler = ar724x_ip3_handler; break; + case AR71XX_SOC_AR9130: case AR71XX_SOC_AR9132: - ar71xx_ip2_irq_handler = ar913x_wmac_irq_dispatch; + ip2_handler = ar913x_ip2_handler; + ip3_handler = ar913x_ip3_handler; + break; + + case AR71XX_SOC_AR9330: + case AR71XX_SOC_AR9331: + ip2_handler = ar933x_ip2_handler; + ip3_handler = ar933x_ip3_handler; break; + + case AR71XX_SOC_AR9341: + case AR71XX_SOC_AR9342: + case AR71XX_SOC_AR9344: + ip2_handler = ar934x_ip2_handler; + ip3_handler = ar934x_ip3_handler; + break; + default: BUG(); } + mips_cpu_irq_init(); + + ar71xx_misc_irq_init(); + + if (ar71xx_soc == AR71XX_SOC_AR9341 || + ar71xx_soc == AR71XX_SOC_AR9342 || + ar71xx_soc == AR71XX_SOC_AR9344) + ar934x_ip2_irq_init(); + + cp0_perfcount_irq = AR71XX_MISC_IRQ_PERFC; + ar71xx_gpio_irq_init(); }