ath79: image: fix initramfs for safeloader devices
[oweals/openwrt.git] / target / linux / ath79 / patches-5.4 / 0007-irqchip-irq-ath79-intc-add-irq-cascade-driver-for-QC.patch
1 From f3eacff2310a60348a755c50a8da6fc251fc8587 Mon Sep 17 00:00:00 2001
2 From: John Crispin <john@phrozen.org>
3 Date: Tue, 6 Mar 2018 09:55:13 +0100
4 Subject: [PATCH 07/33] irqchip/irq-ath79-intc: add irq cascade driver for
5  QCA9556 SoCs
6
7 Signed-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);