hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/irqchip/irq-mmp.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * linux/arch/arm/mach-mmp/irq.c
34 *
....@@ -6,16 +7,13 @@
67 *
78 * Author: Bin Yang <bin.yang@marvell.com>
89 * Haojian Zhuang <haojian.zhuang@gmail.com>
9
- *
10
- * This program is free software; you can redistribute it and/or modify
11
- * it under the terms of the GNU General Public License version 2 as
12
- * published by the Free Software Foundation.
1310 */
1411
1512 #include <linux/module.h>
1613 #include <linux/init.h>
1714 #include <linux/irq.h>
1815 #include <linux/irqchip.h>
16
+#include <linux/irqchip/chained_irq.h>
1917 #include <linux/irqdomain.h>
2018 #include <linux/io.h>
2119 #include <linux/ioport.h>
....@@ -46,6 +44,7 @@
4644 unsigned int conf_enable;
4745 unsigned int conf_disable;
4846 unsigned int conf_mask;
47
+ unsigned int conf2_mask;
4948 unsigned int clr_mfp_irq_base;
5049 unsigned int clr_mfp_hwirq;
5150 struct irq_domain *domain;
....@@ -55,9 +54,11 @@
5554 unsigned int conf_enable;
5655 unsigned int conf_disable;
5756 unsigned int conf_mask;
57
+ unsigned int conf2_mask;
5858 };
5959
6060 static void __iomem *mmp_icu_base;
61
+static void __iomem *mmp_icu2_base;
6162 static struct icu_chip_data icu_data[MAX_ICU_NR];
6263 static int max_icu_nr;
6364
....@@ -100,6 +101,16 @@
100101 r &= ~data->conf_mask;
101102 r |= data->conf_disable;
102103 writel_relaxed(r, mmp_icu_base + (hwirq << 2));
104
+
105
+ if (data->conf2_mask) {
106
+ /*
107
+ * ICU1 (above) only controls PJ4 MP1; if using SMP,
108
+ * we need to also mask the MP2 and MM cores via ICU2.
109
+ */
110
+ r = readl_relaxed(mmp_icu2_base + (hwirq << 2));
111
+ r &= ~data->conf2_mask;
112
+ writel_relaxed(r, mmp_icu2_base + (hwirq << 2));
113
+ }
103114 } else {
104115 r = readl_relaxed(data->reg_mask) | (1 << hwirq);
105116 writel_relaxed(r, data->reg_mask);
....@@ -135,10 +146,13 @@
135146 static void icu_mux_irq_demux(struct irq_desc *desc)
136147 {
137148 unsigned int irq = irq_desc_get_irq(desc);
149
+ struct irq_chip *chip = irq_desc_get_chip(desc);
138150 struct irq_domain *domain;
139151 struct icu_chip_data *data;
140152 int i;
141153 unsigned long mask, status, n;
154
+
155
+ chained_irq_enter(chip, desc);
142156
143157 for (i = 1; i < max_icu_nr; i++) {
144158 if (irq == icu_data[i].cascade_irq) {
....@@ -149,7 +163,7 @@
149163 }
150164 if (i >= max_icu_nr) {
151165 pr_err("Spurious irq %d in MMP INTC\n", irq);
152
- return;
166
+ goto out;
153167 }
154168
155169 mask = readl_relaxed(data->reg_mask);
....@@ -161,6 +175,9 @@
161175 generic_handle_irq(icu_data[i].virq_base + n);
162176 }
163177 }
178
+
179
+out:
180
+ chained_irq_exit(chip, desc);
164181 }
165182
166183 static int mmp_irq_domain_map(struct irq_domain *d, unsigned int irq,
....@@ -179,7 +196,7 @@
179196 return 0;
180197 }
181198
182
-const struct irq_domain_ops mmp_irq_domain_ops = {
199
+static const struct irq_domain_ops mmp_irq_domain_ops = {
183200 .map = mmp_irq_domain_map,
184201 .xlate = mmp_irq_domain_xlate,
185202 };
....@@ -195,6 +212,14 @@
195212 .conf_disable = 0x0,
196213 .conf_mask = MMP2_ICU_INT_ROUTE_PJ4_IRQ |
197214 MMP2_ICU_INT_ROUTE_PJ4_FIQ,
215
+};
216
+
217
+static struct mmp_intc_conf mmp3_conf = {
218
+ .conf_enable = 0x20,
219
+ .conf_disable = 0x0,
220
+ .conf_mask = MMP2_ICU_INT_ROUTE_PJ4_IRQ |
221
+ MMP2_ICU_INT_ROUTE_PJ4_FIQ,
222
+ .conf2_mask = 0xf0,
198223 };
199224
200225 static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs)
....@@ -398,7 +423,6 @@
398423 icu_data[0].conf_enable = mmp_conf.conf_enable;
399424 icu_data[0].conf_disable = mmp_conf.conf_disable;
400425 icu_data[0].conf_mask = mmp_conf.conf_mask;
401
- irq_set_default_host(icu_data[0].domain);
402426 set_handle_irq(mmp_handle_irq);
403427 max_icu_nr = 1;
404428 return 0;
....@@ -417,19 +441,50 @@
417441 icu_data[0].conf_enable = mmp2_conf.conf_enable;
418442 icu_data[0].conf_disable = mmp2_conf.conf_disable;
419443 icu_data[0].conf_mask = mmp2_conf.conf_mask;
420
- irq_set_default_host(icu_data[0].domain);
421444 set_handle_irq(mmp2_handle_irq);
422445 max_icu_nr = 1;
423446 return 0;
424447 }
425448 IRQCHIP_DECLARE(mmp2_intc, "mrvl,mmp2-intc", mmp2_of_init);
426449
450
+static int __init mmp3_of_init(struct device_node *node,
451
+ struct device_node *parent)
452
+{
453
+ int ret;
454
+
455
+ mmp_icu2_base = of_iomap(node, 1);
456
+ if (!mmp_icu2_base) {
457
+ pr_err("Failed to get interrupt controller register #2\n");
458
+ return -ENODEV;
459
+ }
460
+
461
+ ret = mmp_init_bases(node);
462
+ if (ret < 0) {
463
+ iounmap(mmp_icu2_base);
464
+ return ret;
465
+ }
466
+
467
+ icu_data[0].conf_enable = mmp3_conf.conf_enable;
468
+ icu_data[0].conf_disable = mmp3_conf.conf_disable;
469
+ icu_data[0].conf_mask = mmp3_conf.conf_mask;
470
+ icu_data[0].conf2_mask = mmp3_conf.conf2_mask;
471
+
472
+ if (!parent) {
473
+ /* This is the main interrupt controller. */
474
+ set_handle_irq(mmp2_handle_irq);
475
+ }
476
+
477
+ max_icu_nr = 1;
478
+ return 0;
479
+}
480
+IRQCHIP_DECLARE(mmp3_intc, "marvell,mmp3-intc", mmp3_of_init);
481
+
427482 static int __init mmp2_mux_of_init(struct device_node *node,
428483 struct device_node *parent)
429484 {
430
- struct resource res;
431485 int i, ret, irq, j = 0;
432486 u32 nr_irqs, mfp_irq;
487
+ u32 reg[4];
433488
434489 if (!parent)
435490 return -ENODEV;
....@@ -441,18 +496,22 @@
441496 pr_err("Not found mrvl,intc-nr-irqs property\n");
442497 return -EINVAL;
443498 }
444
- ret = of_address_to_resource(node, 0, &res);
499
+
500
+ /*
501
+ * For historical reasons, the "regs" property of the
502
+ * mrvl,mmp2-mux-intc is not a regular "regs" property containing
503
+ * addresses on the parent bus, but offsets from the intc's base.
504
+ * That is why we can't use of_address_to_resource() here.
505
+ */
506
+ ret = of_property_read_variable_u32_array(node, "reg", reg,
507
+ ARRAY_SIZE(reg),
508
+ ARRAY_SIZE(reg));
445509 if (ret < 0) {
446510 pr_err("Not found reg property\n");
447511 return -EINVAL;
448512 }
449
- icu_data[i].reg_status = mmp_icu_base + res.start;
450
- ret = of_address_to_resource(node, 1, &res);
451
- if (ret < 0) {
452
- pr_err("Not found reg property\n");
453
- return -EINVAL;
454
- }
455
- icu_data[i].reg_mask = mmp_icu_base + res.start;
513
+ icu_data[i].reg_status = mmp_icu_base + reg[0];
514
+ icu_data[i].reg_mask = mmp_icu_base + reg[2];
456515 icu_data[i].cascade_irq = irq_of_parse_and_map(node, 0);
457516 if (!icu_data[i].cascade_irq)
458517 return -EINVAL;