1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Renesas RZ/V2H(P) ICU Driver
4 *
5 * Based on irq-renesas-rzg2l.c
6 *
7 * Copyright (C) 2024 Renesas Electronics Corporation.
8 *
9 * Author: Fabrizio Castro <[email protected]>
10 */
11
12 #include <linux/bitfield.h>
13 #include <linux/cleanup.h>
14 #include <linux/clk.h>
15 #include <linux/err.h>
16 #include <linux/io.h>
17 #include <linux/irqchip.h>
18 #include <linux/irqdomain.h>
19 #include <linux/of_address.h>
20 #include <linux/of_platform.h>
21 #include <linux/pm_runtime.h>
22 #include <linux/reset.h>
23 #include <linux/spinlock.h>
24 #include <linux/syscore_ops.h>
25
26 /* DT "interrupts" indexes */
27 #define ICU_IRQ_START 1
28 #define ICU_IRQ_COUNT 16
29 #define ICU_TINT_START (ICU_IRQ_START + ICU_IRQ_COUNT)
30 #define ICU_TINT_COUNT 32
31 #define ICU_NUM_IRQ (ICU_TINT_START + ICU_TINT_COUNT)
32
33 /* Registers */
34 #define ICU_NSCNT 0x00
35 #define ICU_NSCLR 0x04
36 #define ICU_NITSR 0x08
37 #define ICU_ISCTR 0x10
38 #define ICU_ISCLR 0x14
39 #define ICU_IITSR 0x18
40 #define ICU_TSCTR 0x20
41 #define ICU_TSCLR 0x24
42 #define ICU_TITSR(k) (0x28 + (k) * 4)
43 #define ICU_TSSR(k) (0x30 + (k) * 4)
44
45 /* NMI */
46 #define ICU_NMI_EDGE_FALLING 0
47 #define ICU_NMI_EDGE_RISING 1
48
49 #define ICU_NSCLR_NCLR BIT(0)
50
51 /* IRQ */
52 #define ICU_IRQ_LEVEL_LOW 0
53 #define ICU_IRQ_EDGE_FALLING 1
54 #define ICU_IRQ_EDGE_RISING 2
55 #define ICU_IRQ_EDGE_BOTH 3
56
57 #define ICU_IITSR_IITSEL_PREP(iitsel, n) ((iitsel) << ((n) * 2))
58 #define ICU_IITSR_IITSEL_GET(iitsr, n) (((iitsr) >> ((n) * 2)) & 0x03)
59 #define ICU_IITSR_IITSEL_MASK(n) ICU_IITSR_IITSEL_PREP(0x03, n)
60
61 /* TINT */
62 #define ICU_TINT_EDGE_RISING 0
63 #define ICU_TINT_EDGE_FALLING 1
64 #define ICU_TINT_LEVEL_HIGH 2
65 #define ICU_TINT_LEVEL_LOW 3
66
67 #define ICU_TSSR_K(tint_nr) ((tint_nr) / 4)
68 #define ICU_TSSR_TSSEL_N(tint_nr) ((tint_nr) % 4)
69 #define ICU_TSSR_TSSEL_PREP(tssel, n) ((tssel) << ((n) * 8))
70 #define ICU_TSSR_TSSEL_MASK(n) ICU_TSSR_TSSEL_PREP(0x7F, n)
71 #define ICU_TSSR_TIEN(n) (BIT(7) << ((n) * 8))
72
73 #define ICU_TITSR_K(tint_nr) ((tint_nr) / 16)
74 #define ICU_TITSR_TITSEL_N(tint_nr) ((tint_nr) % 16)
75 #define ICU_TITSR_TITSEL_PREP(titsel, n) ICU_IITSR_IITSEL_PREP(titsel, n)
76 #define ICU_TITSR_TITSEL_MASK(n) ICU_IITSR_IITSEL_MASK(n)
77 #define ICU_TITSR_TITSEL_GET(titsr, n) ICU_IITSR_IITSEL_GET(titsr, n)
78
79 #define ICU_TINT_EXTRACT_HWIRQ(x) FIELD_GET(GENMASK(15, 0), (x))
80 #define ICU_TINT_EXTRACT_GPIOINT(x) FIELD_GET(GENMASK(31, 16), (x))
81 #define ICU_PB5_TINT 0x55
82
83 /**
84 * struct rzv2h_icu_priv - Interrupt Control Unit controller private data structure.
85 * @base: Controller's base address
86 * @irqchip: Pointer to struct irq_chip
87 * @fwspec: IRQ firmware specific data
88 * @lock: Lock to serialize access to hardware registers
89 */
90 struct rzv2h_icu_priv {
91 void __iomem *base;
92 const struct irq_chip *irqchip;
93 struct irq_fwspec fwspec[ICU_NUM_IRQ];
94 raw_spinlock_t lock;
95 };
96
irq_data_to_priv(struct irq_data * data)97 static inline struct rzv2h_icu_priv *irq_data_to_priv(struct irq_data *data)
98 {
99 return data->domain->host_data;
100 }
101
rzv2h_icu_eoi(struct irq_data * d)102 static void rzv2h_icu_eoi(struct irq_data *d)
103 {
104 struct rzv2h_icu_priv *priv = irq_data_to_priv(d);
105 unsigned int hw_irq = irqd_to_hwirq(d);
106 unsigned int tintirq_nr;
107 u32 bit;
108
109 scoped_guard(raw_spinlock, &priv->lock) {
110 if (hw_irq >= ICU_TINT_START) {
111 tintirq_nr = hw_irq - ICU_TINT_START;
112 bit = BIT(tintirq_nr);
113 if (!irqd_is_level_type(d))
114 writel_relaxed(bit, priv->base + ICU_TSCLR);
115 } else if (hw_irq >= ICU_IRQ_START) {
116 tintirq_nr = hw_irq - ICU_IRQ_START;
117 bit = BIT(tintirq_nr);
118 if (!irqd_is_level_type(d))
119 writel_relaxed(bit, priv->base + ICU_ISCLR);
120 } else {
121 writel_relaxed(ICU_NSCLR_NCLR, priv->base + ICU_NSCLR);
122 }
123 }
124
125 irq_chip_eoi_parent(d);
126 }
127
rzv2h_tint_irq_endisable(struct irq_data * d,bool enable)128 static void rzv2h_tint_irq_endisable(struct irq_data *d, bool enable)
129 {
130 struct rzv2h_icu_priv *priv = irq_data_to_priv(d);
131 unsigned int hw_irq = irqd_to_hwirq(d);
132 u32 tint_nr, tssel_n, k, tssr;
133
134 if (hw_irq < ICU_TINT_START)
135 return;
136
137 tint_nr = hw_irq - ICU_TINT_START;
138 k = ICU_TSSR_K(tint_nr);
139 tssel_n = ICU_TSSR_TSSEL_N(tint_nr);
140
141 guard(raw_spinlock)(&priv->lock);
142 tssr = readl_relaxed(priv->base + ICU_TSSR(k));
143 if (enable)
144 tssr |= ICU_TSSR_TIEN(tssel_n);
145 else
146 tssr &= ~ICU_TSSR_TIEN(tssel_n);
147 writel_relaxed(tssr, priv->base + ICU_TSSR(k));
148 }
149
rzv2h_icu_irq_disable(struct irq_data * d)150 static void rzv2h_icu_irq_disable(struct irq_data *d)
151 {
152 irq_chip_disable_parent(d);
153 rzv2h_tint_irq_endisable(d, false);
154 }
155
rzv2h_icu_irq_enable(struct irq_data * d)156 static void rzv2h_icu_irq_enable(struct irq_data *d)
157 {
158 rzv2h_tint_irq_endisable(d, true);
159 irq_chip_enable_parent(d);
160 }
161
rzv2h_nmi_set_type(struct irq_data * d,unsigned int type)162 static int rzv2h_nmi_set_type(struct irq_data *d, unsigned int type)
163 {
164 struct rzv2h_icu_priv *priv = irq_data_to_priv(d);
165 u32 sense;
166
167 switch (type & IRQ_TYPE_SENSE_MASK) {
168 case IRQ_TYPE_EDGE_FALLING:
169 sense = ICU_NMI_EDGE_FALLING;
170 break;
171
172 case IRQ_TYPE_EDGE_RISING:
173 sense = ICU_NMI_EDGE_RISING;
174 break;
175
176 default:
177 return -EINVAL;
178 }
179
180 writel_relaxed(sense, priv->base + ICU_NITSR);
181
182 return 0;
183 }
184
rzv2h_clear_irq_int(struct rzv2h_icu_priv * priv,unsigned int hwirq)185 static void rzv2h_clear_irq_int(struct rzv2h_icu_priv *priv, unsigned int hwirq)
186 {
187 unsigned int irq_nr = hwirq - ICU_IRQ_START;
188 u32 isctr, iitsr, iitsel;
189 u32 bit = BIT(irq_nr);
190
191 isctr = readl_relaxed(priv->base + ICU_ISCTR);
192 iitsr = readl_relaxed(priv->base + ICU_IITSR);
193 iitsel = ICU_IITSR_IITSEL_GET(iitsr, irq_nr);
194
195 /*
196 * When level sensing is used, the interrupt flag gets automatically cleared when the
197 * interrupt signal is de-asserted by the source of the interrupt request, therefore clear
198 * the interrupt only for edge triggered interrupts.
199 */
200 if ((isctr & bit) && (iitsel != ICU_IRQ_LEVEL_LOW))
201 writel_relaxed(bit, priv->base + ICU_ISCLR);
202 }
203
rzv2h_irq_set_type(struct irq_data * d,unsigned int type)204 static int rzv2h_irq_set_type(struct irq_data *d, unsigned int type)
205 {
206 struct rzv2h_icu_priv *priv = irq_data_to_priv(d);
207 unsigned int hwirq = irqd_to_hwirq(d);
208 u32 irq_nr = hwirq - ICU_IRQ_START;
209 u32 iitsr, sense;
210
211 switch (type & IRQ_TYPE_SENSE_MASK) {
212 case IRQ_TYPE_LEVEL_LOW:
213 sense = ICU_IRQ_LEVEL_LOW;
214 break;
215
216 case IRQ_TYPE_EDGE_FALLING:
217 sense = ICU_IRQ_EDGE_FALLING;
218 break;
219
220 case IRQ_TYPE_EDGE_RISING:
221 sense = ICU_IRQ_EDGE_RISING;
222 break;
223
224 case IRQ_TYPE_EDGE_BOTH:
225 sense = ICU_IRQ_EDGE_BOTH;
226 break;
227
228 default:
229 return -EINVAL;
230 }
231
232 guard(raw_spinlock)(&priv->lock);
233 iitsr = readl_relaxed(priv->base + ICU_IITSR);
234 iitsr &= ~ICU_IITSR_IITSEL_MASK(irq_nr);
235 iitsr |= ICU_IITSR_IITSEL_PREP(sense, irq_nr);
236 rzv2h_clear_irq_int(priv, hwirq);
237 writel_relaxed(iitsr, priv->base + ICU_IITSR);
238
239 return 0;
240 }
241
rzv2h_clear_tint_int(struct rzv2h_icu_priv * priv,unsigned int hwirq)242 static void rzv2h_clear_tint_int(struct rzv2h_icu_priv *priv, unsigned int hwirq)
243 {
244 unsigned int tint_nr = hwirq - ICU_TINT_START;
245 int titsel_n = ICU_TITSR_TITSEL_N(tint_nr);
246 u32 tsctr, titsr, titsel;
247 u32 bit = BIT(tint_nr);
248 int k = tint_nr / 16;
249
250 tsctr = readl_relaxed(priv->base + ICU_TSCTR);
251 titsr = readl_relaxed(priv->base + ICU_TITSR(k));
252 titsel = ICU_TITSR_TITSEL_GET(titsr, titsel_n);
253
254 /*
255 * Writing 1 to the corresponding flag from register ICU_TSCTR only has effect if
256 * TSTATn = 1b and if it's a rising edge or a falling edge interrupt.
257 */
258 if ((tsctr & bit) && ((titsel == ICU_TINT_EDGE_RISING) ||
259 (titsel == ICU_TINT_EDGE_FALLING)))
260 writel_relaxed(bit, priv->base + ICU_TSCLR);
261 }
262
rzv2h_tint_set_type(struct irq_data * d,unsigned int type)263 static int rzv2h_tint_set_type(struct irq_data *d, unsigned int type)
264 {
265 u32 titsr, titsr_k, titsel_n, tien;
266 struct rzv2h_icu_priv *priv;
267 u32 tssr, tssr_k, tssel_n;
268 unsigned int hwirq;
269 u32 tint, sense;
270 int tint_nr;
271
272 switch (type & IRQ_TYPE_SENSE_MASK) {
273 case IRQ_TYPE_LEVEL_LOW:
274 sense = ICU_TINT_LEVEL_LOW;
275 break;
276
277 case IRQ_TYPE_LEVEL_HIGH:
278 sense = ICU_TINT_LEVEL_HIGH;
279 break;
280
281 case IRQ_TYPE_EDGE_RISING:
282 sense = ICU_TINT_EDGE_RISING;
283 break;
284
285 case IRQ_TYPE_EDGE_FALLING:
286 sense = ICU_TINT_EDGE_FALLING;
287 break;
288
289 default:
290 return -EINVAL;
291 }
292
293 tint = (u32)(uintptr_t)irq_data_get_irq_chip_data(d);
294 if (tint > ICU_PB5_TINT)
295 return -EINVAL;
296
297 priv = irq_data_to_priv(d);
298 hwirq = irqd_to_hwirq(d);
299
300 tint_nr = hwirq - ICU_TINT_START;
301
302 tssr_k = ICU_TSSR_K(tint_nr);
303 tssel_n = ICU_TSSR_TSSEL_N(tint_nr);
304 tien = ICU_TSSR_TIEN(tssel_n);
305
306 titsr_k = ICU_TITSR_K(tint_nr);
307 titsel_n = ICU_TITSR_TITSEL_N(tint_nr);
308
309 guard(raw_spinlock)(&priv->lock);
310
311 tssr = readl_relaxed(priv->base + ICU_TSSR(tssr_k));
312 tssr &= ~(ICU_TSSR_TSSEL_MASK(tssel_n) | tien);
313 tssr |= ICU_TSSR_TSSEL_PREP(tint, tssel_n);
314
315 writel_relaxed(tssr, priv->base + ICU_TSSR(tssr_k));
316
317 titsr = readl_relaxed(priv->base + ICU_TITSR(titsr_k));
318 titsr &= ~ICU_TITSR_TITSEL_MASK(titsel_n);
319 titsr |= ICU_TITSR_TITSEL_PREP(sense, titsel_n);
320
321 writel_relaxed(titsr, priv->base + ICU_TITSR(titsr_k));
322
323 rzv2h_clear_tint_int(priv, hwirq);
324
325 writel_relaxed(tssr | tien, priv->base + ICU_TSSR(tssr_k));
326
327 return 0;
328 }
329
rzv2h_icu_set_type(struct irq_data * d,unsigned int type)330 static int rzv2h_icu_set_type(struct irq_data *d, unsigned int type)
331 {
332 unsigned int hw_irq = irqd_to_hwirq(d);
333 int ret;
334
335 if (hw_irq >= ICU_TINT_START)
336 ret = rzv2h_tint_set_type(d, type);
337 else if (hw_irq >= ICU_IRQ_START)
338 ret = rzv2h_irq_set_type(d, type);
339 else
340 ret = rzv2h_nmi_set_type(d, type);
341
342 if (ret)
343 return ret;
344
345 return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
346 }
347
348 static const struct irq_chip rzv2h_icu_chip = {
349 .name = "rzv2h-icu",
350 .irq_eoi = rzv2h_icu_eoi,
351 .irq_mask = irq_chip_mask_parent,
352 .irq_unmask = irq_chip_unmask_parent,
353 .irq_disable = rzv2h_icu_irq_disable,
354 .irq_enable = rzv2h_icu_irq_enable,
355 .irq_get_irqchip_state = irq_chip_get_parent_state,
356 .irq_set_irqchip_state = irq_chip_set_parent_state,
357 .irq_retrigger = irq_chip_retrigger_hierarchy,
358 .irq_set_type = rzv2h_icu_set_type,
359 .irq_set_affinity = irq_chip_set_affinity_parent,
360 .flags = IRQCHIP_SET_TYPE_MASKED,
361 };
362
rzv2h_icu_alloc(struct irq_domain * domain,unsigned int virq,unsigned int nr_irqs,void * arg)363 static int rzv2h_icu_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs,
364 void *arg)
365 {
366 struct rzv2h_icu_priv *priv = domain->host_data;
367 unsigned long tint = 0;
368 irq_hw_number_t hwirq;
369 unsigned int type;
370 int ret;
371
372 ret = irq_domain_translate_twocell(domain, arg, &hwirq, &type);
373 if (ret)
374 return ret;
375
376 /*
377 * For TINT interrupts the hwirq and TINT are encoded in
378 * fwspec->param[0].
379 * hwirq is embedded in bits 0-15.
380 * TINT is embedded in bits 16-31.
381 */
382 if (hwirq >= ICU_TINT_START) {
383 tint = ICU_TINT_EXTRACT_GPIOINT(hwirq);
384 hwirq = ICU_TINT_EXTRACT_HWIRQ(hwirq);
385
386 if (hwirq < ICU_TINT_START)
387 return -EINVAL;
388 }
389
390 if (hwirq > (ICU_NUM_IRQ - 1))
391 return -EINVAL;
392
393 ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, priv->irqchip,
394 (void *)(uintptr_t)tint);
395 if (ret)
396 return ret;
397
398 return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &priv->fwspec[hwirq]);
399 }
400
401 static const struct irq_domain_ops rzv2h_icu_domain_ops = {
402 .alloc = rzv2h_icu_alloc,
403 .free = irq_domain_free_irqs_common,
404 .translate = irq_domain_translate_twocell,
405 };
406
rzv2h_icu_parse_interrupts(struct rzv2h_icu_priv * priv,struct device_node * np)407 static int rzv2h_icu_parse_interrupts(struct rzv2h_icu_priv *priv, struct device_node *np)
408 {
409 struct of_phandle_args map;
410 unsigned int i;
411 int ret;
412
413 for (i = 0; i < ICU_NUM_IRQ; i++) {
414 ret = of_irq_parse_one(np, i, &map);
415 if (ret)
416 return ret;
417
418 of_phandle_args_to_fwspec(np, map.args, map.args_count, &priv->fwspec[i]);
419 }
420
421 return 0;
422 }
423
rzv2h_icu_init(struct device_node * node,struct device_node * parent)424 static int rzv2h_icu_init(struct device_node *node, struct device_node *parent)
425 {
426 struct irq_domain *irq_domain, *parent_domain;
427 struct rzv2h_icu_priv *rzv2h_icu_data;
428 struct platform_device *pdev;
429 struct reset_control *resetn;
430 int ret;
431
432 pdev = of_find_device_by_node(node);
433 if (!pdev)
434 return -ENODEV;
435
436 parent_domain = irq_find_host(parent);
437 if (!parent_domain) {
438 dev_err(&pdev->dev, "cannot find parent domain\n");
439 ret = -ENODEV;
440 goto put_dev;
441 }
442
443 rzv2h_icu_data = devm_kzalloc(&pdev->dev, sizeof(*rzv2h_icu_data), GFP_KERNEL);
444 if (!rzv2h_icu_data) {
445 ret = -ENOMEM;
446 goto put_dev;
447 }
448
449 rzv2h_icu_data->irqchip = &rzv2h_icu_chip;
450
451 rzv2h_icu_data->base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL);
452 if (IS_ERR(rzv2h_icu_data->base)) {
453 ret = PTR_ERR(rzv2h_icu_data->base);
454 goto put_dev;
455 }
456
457 ret = rzv2h_icu_parse_interrupts(rzv2h_icu_data, node);
458 if (ret) {
459 dev_err(&pdev->dev, "cannot parse interrupts: %d\n", ret);
460 goto put_dev;
461 }
462
463 resetn = devm_reset_control_get_exclusive(&pdev->dev, NULL);
464 if (IS_ERR(resetn)) {
465 ret = PTR_ERR(resetn);
466 goto put_dev;
467 }
468
469 ret = reset_control_deassert(resetn);
470 if (ret) {
471 dev_err(&pdev->dev, "failed to deassert resetn pin, %d\n", ret);
472 goto put_dev;
473 }
474
475 pm_runtime_enable(&pdev->dev);
476 ret = pm_runtime_resume_and_get(&pdev->dev);
477 if (ret < 0) {
478 dev_err(&pdev->dev, "pm_runtime_resume_and_get failed: %d\n", ret);
479 goto pm_disable;
480 }
481
482 raw_spin_lock_init(&rzv2h_icu_data->lock);
483
484 irq_domain = irq_domain_add_hierarchy(parent_domain, 0, ICU_NUM_IRQ, node,
485 &rzv2h_icu_domain_ops, rzv2h_icu_data);
486 if (!irq_domain) {
487 dev_err(&pdev->dev, "failed to add irq domain\n");
488 ret = -ENOMEM;
489 goto pm_put;
490 }
491
492 /*
493 * coccicheck complains about a missing put_device call before returning, but it's a false
494 * positive. We still need &pdev->dev after successfully returning from this function.
495 */
496 return 0;
497
498 pm_put:
499 pm_runtime_put(&pdev->dev);
500 pm_disable:
501 pm_runtime_disable(&pdev->dev);
502 reset_control_assert(resetn);
503 put_dev:
504 put_device(&pdev->dev);
505
506 return ret;
507 }
508
509 IRQCHIP_PLATFORM_DRIVER_BEGIN(rzv2h_icu)
510 IRQCHIP_MATCH("renesas,r9a09g057-icu", rzv2h_icu_init)
511 IRQCHIP_PLATFORM_DRIVER_END(rzv2h_icu)
512 MODULE_AUTHOR("Fabrizio Castro <[email protected]>");
513 MODULE_DESCRIPTION("Renesas RZ/V2H(P) ICU Driver");
514