blob: ceda511c21af7c2e1396bb8ef8727c76028a93ec [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001From f3eacff2310a60348a755c50a8da6fc251fc8587 Mon Sep 17 00:00:00 2001
2From: John Crispin <john@phrozen.org>
3Date: Tue, 6 Mar 2018 09:55:13 +0100
4Subject: [PATCH 07/33] irqchip/irq-ath79-intc: add irq cascade driver for
5 QCA9556 SoCs
6
7Signed-off-by: John Crispin <john@phrozen.org>
8---
9 drivers/irqchip/Makefile | 1 +
10 drivers/irqchip/irq-ath79-intc.c | 142 +++++++++++++++++++++++++++++++++++++++
11 2 files changed, 143 insertions(+)
12 create mode 100644 drivers/irqchip/irq-ath79-intc.c
13
14--- a/drivers/irqchip/Makefile
15+++ b/drivers/irqchip/Makefile
16@@ -4,6 +4,7 @@ obj-$(CONFIG_IRQCHIP) += irqchip.o
17 obj-$(CONFIG_AL_FIC) += irq-al-fic.o
18 obj-$(CONFIG_ALPINE_MSI) += irq-alpine-msi.o
19 obj-$(CONFIG_ATH79) += irq-ath79-cpu.o
20+obj-$(CONFIG_ATH79) += irq-ath79-intc.o
21 obj-$(CONFIG_ATH79) += irq-ath79-misc.o
22 obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o
23 obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2836.o
24--- /dev/null
25+++ b/drivers/irqchip/irq-ath79-intc.c
26@@ -0,0 +1,142 @@
27+/*
28+ * Atheros AR71xx/AR724x/AR913x specific interrupt handling
29+ *
30+ * Copyright (C) 2018 John Crispin <john@phrozen.org>
31+ *
32+ * This program is free software; you can redistribute it and/or modify it
33+ * under the terms of the GNU General Public License version 2 as published
34+ * by the Free Software Foundation.
35+ */
36+
37+#include <linux/interrupt.h>
38+#include <linux/irqchip.h>
39+#include <linux/of.h>
40+#include <linux/of_irq.h>
41+#include <linux/irqdomain.h>
42+
43+#include <asm/irq_cpu.h>
44+#include <asm/mach-ath79/ath79.h>
45+#include <asm/mach-ath79/ar71xx_regs.h>
46+
47+#define ATH79_MAX_INTC_CASCADE 3
48+
49+struct ath79_intc {
50+ struct irq_chip chip;
51+ u32 irq;
52+ u32 pending_mask;
53+ u32 int_status;
54+ u32 irq_mask[ATH79_MAX_INTC_CASCADE];
55+ u32 irq_wb_chan[ATH79_MAX_INTC_CASCADE];
56+};
57+
58+static void ath79_intc_irq_handler(struct irq_desc *desc)
59+{
60+ struct irq_domain *domain = irq_desc_get_handler_data(desc);
61+ struct ath79_intc *intc = domain->host_data;
62+ u32 pending;
63+
64+ pending = ath79_reset_rr(intc->int_status);
65+ pending &= intc->pending_mask;
66+
67+ if (pending) {
68+ int i;
69+
70+ for (i = 0; i < domain->hwirq_max; i++)
71+ if (pending & intc->irq_mask[i]) {
72+ if (intc->irq_wb_chan[i] != 0xffffffff)
73+ ath79_ddr_wb_flush(intc->irq_wb_chan[i]);
74+ generic_handle_irq(irq_find_mapping(domain, i));
75+ }
76+ } else {
77+ spurious_interrupt();
78+ }
79+}
80+
81+static void ath79_intc_irq_enable(struct irq_data *d)
82+{
83+ struct ath79_intc *intc = d->domain->host_data;
84+ enable_irq(intc->irq);
85+}
86+
87+static void ath79_intc_irq_disable(struct irq_data *d)
88+{
89+ struct ath79_intc *intc = d->domain->host_data;
90+ disable_irq(intc->irq);
91+}
92+
93+static int ath79_intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
94+{
95+ struct ath79_intc *intc = d->host_data;
96+
97+ irq_set_chip_and_handler(irq, &intc->chip, handle_level_irq);
98+
99+ return 0;
100+}
101+
102+static const struct irq_domain_ops ath79_irq_domain_ops = {
103+ .xlate = irq_domain_xlate_onecell,
104+ .map = ath79_intc_map,
105+};
106+
107+static int __init ath79_intc_of_init(
108+ struct device_node *node, struct device_node *parent)
109+{
110+ struct irq_domain *domain;
111+ struct ath79_intc *intc;
112+ int cnt, cntwb, i, err;
113+
114+ cnt = of_property_count_u32_elems(node, "qca,pending-bits");
115+ if (cnt > ATH79_MAX_INTC_CASCADE)
116+ panic("Too many INTC pending bits\n");
117+
118+ intc = kzalloc(sizeof(*intc), GFP_KERNEL);
119+ if (!intc)
120+ panic("Failed to allocate INTC memory\n");
121+ intc->chip = dummy_irq_chip;
122+ intc->chip.name = "INTC";
123+ intc->chip.irq_disable = ath79_intc_irq_disable;
124+ intc->chip.irq_enable = ath79_intc_irq_enable;
125+
126+ if (of_property_read_u32(node, "qca,int-status-addr", &intc->int_status) < 0) {
127+ panic("Missing address of interrupt status register\n");
128+ }
129+
130+ of_property_read_u32_array(node, "qca,pending-bits", intc->irq_mask, cnt);
131+ for (i = 0; i < cnt; i++) {
132+ intc->pending_mask |= intc->irq_mask[i];
133+ intc->irq_wb_chan[i] = 0xffffffff;
134+ }
135+
136+ cntwb = of_count_phandle_with_args(
137+ node, "qca,ddr-wb-channels", "#qca,ddr-wb-channel-cells");
138+
139+ for (i = 0; i < cntwb; i++) {
140+ struct of_phandle_args args;
141+ u32 irq = i;
142+
143+ of_property_read_u32_index(
144+ node, "qca,ddr-wb-channel-interrupts", i, &irq);
145+ if (irq >= ATH79_MAX_INTC_CASCADE)
146+ continue;
147+
148+ err = of_parse_phandle_with_args(
149+ node, "qca,ddr-wb-channels",
150+ "#qca,ddr-wb-channel-cells",
151+ i, &args);
152+ if (err)
153+ return err;
154+
155+ intc->irq_wb_chan[irq] = args.args[0];
156+ }
157+
158+ intc->irq = irq_of_parse_and_map(node, 0);
159+ if (!intc->irq)
160+ panic("Failed to get INTC IRQ");
161+
162+ domain = irq_domain_add_linear(node, cnt, &ath79_irq_domain_ops, intc);
163+ irq_set_chained_handler_and_data(intc->irq, ath79_intc_irq_handler, domain);
164+
165+ return 0;
166+}
167+IRQCHIP_DECLARE(ath79_intc, "qca,ar9340-intc",
168+ ath79_intc_of_init);