···11+/*22+ * Atheros AR71xx/AR724x/AR913x specific interrupt handling33+ *44+ * Copyright (C) 2015 Alban Bedel <albeu@free.fr>55+ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>66+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>77+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>88+ *99+ * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP1010+ *1111+ * This program is free software; you can redistribute it and/or modify it1212+ * under the terms of the GNU General Public License version 2 as published1313+ * by the Free Software Foundation.1414+ */1515+1616+#include <linux/interrupt.h>1717+#include <linux/irqchip.h>1818+#include <linux/of.h>1919+2020+#include <asm/irq_cpu.h>2121+#include <asm/mach-ath79/ath79.h>2222+2323+/*2424+ * The IP2/IP3 lines are tied to a PCI/WMAC/USB device. Drivers for2525+ * these devices typically allocate coherent DMA memory, however the2626+ * DMA controller may still have some unsynchronized data in the FIFO.2727+ * Issue a flush in the handlers to ensure that the driver sees2828+ * the update.2929+ *3030+ * This array map the interrupt lines to the DDR write buffer channels.3131+ */3232+3333+static unsigned irq_wb_chan[8] = {3434+ -1, -1, -1, -1, -1, -1, -1, -1,3535+};3636+3737+asmlinkage void plat_irq_dispatch(void)3838+{3939+ unsigned long pending;4040+ int irq;4141+4242+ pending = read_c0_status() & read_c0_cause() & ST0_IM;4343+4444+ if (!pending) {4545+ spurious_interrupt();4646+ return;4747+ }4848+4949+ pending >>= CAUSEB_IP;5050+ while (pending) {5151+ irq = fls(pending) - 1;5252+ if (irq < ARRAY_SIZE(irq_wb_chan) && irq_wb_chan[irq] != -1)5353+ ath79_ddr_wb_flush(irq_wb_chan[irq]);5454+ do_IRQ(MIPS_CPU_IRQ_BASE + irq);5555+ pending &= ~BIT(irq);5656+ }5757+}5858+5959+static int __init ar79_cpu_intc_of_init(6060+ struct device_node *node, struct device_node *parent)6161+{6262+ int err, i, count;6363+6464+ /* Fill the irq_wb_chan table */6565+ count = of_count_phandle_with_args(6666+ node, "qca,ddr-wb-channels", "#qca,ddr-wb-channel-cells");6767+6868+ for (i = 0; i < count; i++) {6969+ struct of_phandle_args args;7070+ u32 irq = i;7171+7272+ of_property_read_u32_index(7373+ node, "qca,ddr-wb-channel-interrupts", i, &irq);7474+ if (irq >= ARRAY_SIZE(irq_wb_chan))7575+ continue;7676+7777+ err = of_parse_phandle_with_args(7878+ node, "qca,ddr-wb-channels",7979+ "#qca,ddr-wb-channel-cells",8080+ i, &args);8181+ if (err)8282+ return err;8383+8484+ irq_wb_chan[irq] = args.args[0];8585+ }8686+8787+ return mips_cpu_irq_of_init(node, parent);8888+}8989+IRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar7100-cpu-intc",9090+ ar79_cpu_intc_of_init);9191+9292+void __init ath79_cpu_irq_init(unsigned irq_wb_chan2, unsigned irq_wb_chan3)9393+{9494+ irq_wb_chan[2] = irq_wb_chan2;9595+ irq_wb_chan[3] = irq_wb_chan3;9696+ mips_cpu_irq_init();9797+}
+189
drivers/irqchip/irq-ath79-misc.c
···11+/*22+ * Atheros AR71xx/AR724x/AR913x MISC interrupt controller33+ *44+ * Copyright (C) 2015 Alban Bedel <albeu@free.fr>55+ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>66+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>77+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>88+ *99+ * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP1010+ *1111+ * This program is free software; you can redistribute it and/or modify it1212+ * under the terms of the GNU General Public License version 2 as published1313+ * by the Free Software Foundation.1414+ */1515+1616+#include <linux/irqchip.h>1717+#include <linux/irqchip/chained_irq.h>1818+#include <linux/of_address.h>1919+#include <linux/of_irq.h>2020+2121+#define AR71XX_RESET_REG_MISC_INT_STATUS 02222+#define AR71XX_RESET_REG_MISC_INT_ENABLE 42323+2424+#define ATH79_MISC_IRQ_COUNT 322525+2626+static void ath79_misc_irq_handler(struct irq_desc *desc)2727+{2828+ struct irq_domain *domain = irq_desc_get_handler_data(desc);2929+ struct irq_chip *chip = irq_desc_get_chip(desc);3030+ void __iomem *base = domain->host_data;3131+ u32 pending;3232+3333+ chained_irq_enter(chip, desc);3434+3535+ pending = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS) &3636+ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);3737+3838+ if (!pending) {3939+ spurious_interrupt();4040+ chained_irq_exit(chip, desc);4141+ return;4242+ }4343+4444+ while (pending) {4545+ int bit = __ffs(pending);4646+4747+ generic_handle_irq(irq_linear_revmap(domain, bit));4848+ pending &= ~BIT(bit);4949+ }5050+5151+ chained_irq_exit(chip, desc);5252+}5353+5454+static void ar71xx_misc_irq_unmask(struct irq_data *d)5555+{5656+ void __iomem *base = irq_data_get_irq_chip_data(d);5757+ unsigned int irq = d->hwirq;5858+ u32 t;5959+6060+ t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);6161+ __raw_writel(t | BIT(irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);6262+6363+ /* flush write */6464+ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);6565+}6666+6767+static void ar71xx_misc_irq_mask(struct irq_data *d)6868+{6969+ void __iomem *base = irq_data_get_irq_chip_data(d);7070+ unsigned int irq = d->hwirq;7171+ u32 t;7272+7373+ t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);7474+ __raw_writel(t & ~BIT(irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);7575+7676+ /* flush write */7777+ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);7878+}7979+8080+static void ar724x_misc_irq_ack(struct irq_data *d)8181+{8282+ void __iomem *base = irq_data_get_irq_chip_data(d);8383+ unsigned int irq = d->hwirq;8484+ u32 t;8585+8686+ t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);8787+ __raw_writel(t & ~BIT(irq), base + AR71XX_RESET_REG_MISC_INT_STATUS);8888+8989+ /* flush write */9090+ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);9191+}9292+9393+static struct irq_chip ath79_misc_irq_chip = {9494+ .name = "MISC",9595+ .irq_unmask = ar71xx_misc_irq_unmask,9696+ .irq_mask = ar71xx_misc_irq_mask,9797+};9898+9999+static int misc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)100100+{101101+ irq_set_chip_and_handler(irq, &ath79_misc_irq_chip, handle_level_irq);102102+ irq_set_chip_data(irq, d->host_data);103103+ return 0;104104+}105105+106106+static const struct irq_domain_ops misc_irq_domain_ops = {107107+ .xlate = irq_domain_xlate_onecell,108108+ .map = misc_map,109109+};110110+111111+static void __init ath79_misc_intc_domain_init(112112+ struct irq_domain *domain, int irq)113113+{114114+ void __iomem *base = domain->host_data;115115+116116+ /* Disable and clear all interrupts */117117+ __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE);118118+ __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS);119119+120120+ irq_set_chained_handler_and_data(irq, ath79_misc_irq_handler, domain);121121+}122122+123123+static int __init ath79_misc_intc_of_init(124124+ struct device_node *node, struct device_node *parent)125125+{126126+ struct irq_domain *domain;127127+ void __iomem *base;128128+ int irq;129129+130130+ irq = irq_of_parse_and_map(node, 0);131131+ if (!irq) {132132+ pr_err("Failed to get MISC IRQ\n");133133+ return -EINVAL;134134+ }135135+136136+ base = of_iomap(node, 0);137137+ if (!base) {138138+ pr_err("Failed to get MISC IRQ registers\n");139139+ return -ENOMEM;140140+ }141141+142142+ domain = irq_domain_add_linear(node, ATH79_MISC_IRQ_COUNT,143143+ &misc_irq_domain_ops, base);144144+ if (!domain) {145145+ pr_err("Failed to add MISC irqdomain\n");146146+ return -EINVAL;147147+ }148148+149149+ ath79_misc_intc_domain_init(domain, irq);150150+ return 0;151151+}152152+153153+static int __init ar7100_misc_intc_of_init(154154+ struct device_node *node, struct device_node *parent)155155+{156156+ ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;157157+ return ath79_misc_intc_of_init(node, parent);158158+}159159+160160+IRQCHIP_DECLARE(ar7100_misc_intc, "qca,ar7100-misc-intc",161161+ ar7100_misc_intc_of_init);162162+163163+static int __init ar7240_misc_intc_of_init(164164+ struct device_node *node, struct device_node *parent)165165+{166166+ ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;167167+ return ath79_misc_intc_of_init(node, parent);168168+}169169+170170+IRQCHIP_DECLARE(ar7240_misc_intc, "qca,ar7240-misc-intc",171171+ ar7240_misc_intc_of_init);172172+173173+void __init ath79_misc_irq_init(void __iomem *regs, int irq,174174+ int irq_base, bool is_ar71xx)175175+{176176+ struct irq_domain *domain;177177+178178+ if (is_ar71xx)179179+ ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;180180+ else181181+ ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;182182+183183+ domain = irq_domain_add_legacy(NULL, ATH79_MISC_IRQ_COUNT,184184+ irq_base, 0, &misc_irq_domain_ops, regs);185185+ if (!domain)186186+ panic("Failed to create MISC irqdomain");187187+188188+ ath79_misc_intc_domain_init(domain, irq);189189+}