1 // SPDX-License-Identifier: GPL-2.0
3 * Renesas RZ/V2H(P) ICU Driver
5 * Based on irq-renesas-rzg2l.c
7 * Copyright (C) 2024 Renesas Electronics Corporation.
9 * Author: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
12 #include <linux/bitfield.h>
13 #include <linux/cleanup.h>
14 #include <linux/clk.h>
15 #include <linux/err.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>
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)
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)
46 #define ICU_NMI_EDGE_FALLING 0
47 #define ICU_NMI_EDGE_RISING 1
49 #define ICU_NSCLR_NCLR BIT(0)
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
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)
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
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))
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)
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
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
90 struct rzv2h_icu_priv
{
92 const struct irq_chip
*irqchip
;
93 struct irq_fwspec fwspec
[ICU_NUM_IRQ
];
97 static inline struct rzv2h_icu_priv
*irq_data_to_priv(struct irq_data
*data
)
99 return data
->domain
->host_data
;
102 static void rzv2h_icu_eoi(struct irq_data
*d
)
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
;
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
);
121 writel_relaxed(ICU_NSCLR_NCLR
, priv
->base
+ ICU_NSCLR
);
125 irq_chip_eoi_parent(d
);
128 static void rzv2h_tint_irq_endisable(struct irq_data
*d
, bool enable
)
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
;
134 if (hw_irq
< ICU_TINT_START
)
137 tint_nr
= hw_irq
- ICU_TINT_START
;
138 k
= ICU_TSSR_K(tint_nr
);
139 tssel_n
= ICU_TSSR_TSSEL_N(tint_nr
);
141 guard(raw_spinlock
)(&priv
->lock
);
142 tssr
= readl_relaxed(priv
->base
+ ICU_TSSR(k
));
144 tssr
|= ICU_TSSR_TIEN(tssel_n
);
146 tssr
&= ~ICU_TSSR_TIEN(tssel_n
);
147 writel_relaxed(tssr
, priv
->base
+ ICU_TSSR(k
));
150 static void rzv2h_icu_irq_disable(struct irq_data
*d
)
152 irq_chip_disable_parent(d
);
153 rzv2h_tint_irq_endisable(d
, false);
156 static void rzv2h_icu_irq_enable(struct irq_data
*d
)
158 rzv2h_tint_irq_endisable(d
, true);
159 irq_chip_enable_parent(d
);
162 static int rzv2h_nmi_set_type(struct irq_data
*d
, unsigned int type
)
164 struct rzv2h_icu_priv
*priv
= irq_data_to_priv(d
);
167 switch (type
& IRQ_TYPE_SENSE_MASK
) {
168 case IRQ_TYPE_EDGE_FALLING
:
169 sense
= ICU_NMI_EDGE_FALLING
;
172 case IRQ_TYPE_EDGE_RISING
:
173 sense
= ICU_NMI_EDGE_RISING
;
180 writel_relaxed(sense
, priv
->base
+ ICU_NITSR
);
185 static void rzv2h_clear_irq_int(struct rzv2h_icu_priv
*priv
, unsigned int hwirq
)
187 unsigned int irq_nr
= hwirq
- ICU_IRQ_START
;
188 u32 isctr
, iitsr
, iitsel
;
189 u32 bit
= BIT(irq_nr
);
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
);
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.
200 if ((isctr
& bit
) && (iitsel
!= ICU_IRQ_LEVEL_LOW
))
201 writel_relaxed(bit
, priv
->base
+ ICU_ISCLR
);
204 static int rzv2h_irq_set_type(struct irq_data
*d
, unsigned int type
)
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
;
211 switch (type
& IRQ_TYPE_SENSE_MASK
) {
212 case IRQ_TYPE_LEVEL_LOW
:
213 sense
= ICU_IRQ_LEVEL_LOW
;
216 case IRQ_TYPE_EDGE_FALLING
:
217 sense
= ICU_IRQ_EDGE_FALLING
;
220 case IRQ_TYPE_EDGE_RISING
:
221 sense
= ICU_IRQ_EDGE_RISING
;
224 case IRQ_TYPE_EDGE_BOTH
:
225 sense
= ICU_IRQ_EDGE_BOTH
;
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
);
242 static void rzv2h_clear_tint_int(struct rzv2h_icu_priv
*priv
, unsigned int hwirq
)
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;
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
);
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.
258 if ((tsctr
& bit
) && ((titsel
== ICU_TINT_EDGE_RISING
) ||
259 (titsel
== ICU_TINT_EDGE_FALLING
)))
260 writel_relaxed(bit
, priv
->base
+ ICU_TSCLR
);
263 static int rzv2h_tint_set_type(struct irq_data
*d
, unsigned int type
)
265 u32 titsr
, titsr_k
, titsel_n
, tien
;
266 struct rzv2h_icu_priv
*priv
;
267 u32 tssr
, tssr_k
, tssel_n
;
272 switch (type
& IRQ_TYPE_SENSE_MASK
) {
273 case IRQ_TYPE_LEVEL_LOW
:
274 sense
= ICU_TINT_LEVEL_LOW
;
277 case IRQ_TYPE_LEVEL_HIGH
:
278 sense
= ICU_TINT_LEVEL_HIGH
;
281 case IRQ_TYPE_EDGE_RISING
:
282 sense
= ICU_TINT_EDGE_RISING
;
285 case IRQ_TYPE_EDGE_FALLING
:
286 sense
= ICU_TINT_EDGE_FALLING
;
293 tint
= (u32
)(uintptr_t)irq_data_get_irq_chip_data(d
);
294 if (tint
> ICU_PB5_TINT
)
297 priv
= irq_data_to_priv(d
);
298 hwirq
= irqd_to_hwirq(d
);
300 tint_nr
= hwirq
- ICU_TINT_START
;
302 tssr_k
= ICU_TSSR_K(tint_nr
);
303 tssel_n
= ICU_TSSR_TSSEL_N(tint_nr
);
305 titsr_k
= ICU_TITSR_K(tint_nr
);
306 titsel_n
= ICU_TITSR_TITSEL_N(tint_nr
);
307 tien
= ICU_TSSR_TIEN(titsel_n
);
309 guard(raw_spinlock
)(&priv
->lock
);
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
);
315 writel_relaxed(tssr
, priv
->base
+ ICU_TSSR(tssr_k
));
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
);
321 writel_relaxed(titsr
, priv
->base
+ ICU_TITSR(titsr_k
));
323 rzv2h_clear_tint_int(priv
, hwirq
);
325 writel_relaxed(tssr
| tien
, priv
->base
+ ICU_TSSR(tssr_k
));
330 static int rzv2h_icu_set_type(struct irq_data
*d
, unsigned int type
)
332 unsigned int hw_irq
= irqd_to_hwirq(d
);
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
);
340 ret
= rzv2h_nmi_set_type(d
, type
);
345 return irq_chip_set_type_parent(d
, IRQ_TYPE_LEVEL_HIGH
);
348 static const struct irq_chip rzv2h_icu_chip
= {
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
,
363 static int rzv2h_icu_alloc(struct irq_domain
*domain
, unsigned int virq
, unsigned int nr_irqs
,
366 struct rzv2h_icu_priv
*priv
= domain
->host_data
;
367 unsigned long tint
= 0;
368 irq_hw_number_t hwirq
;
372 ret
= irq_domain_translate_twocell(domain
, arg
, &hwirq
, &type
);
377 * For TINT interrupts the hwirq and TINT are encoded in
379 * hwirq is embedded in bits 0-15.
380 * TINT is embedded in bits 16-31.
382 if (hwirq
>= ICU_TINT_START
) {
383 tint
= ICU_TINT_EXTRACT_GPIOINT(hwirq
);
384 hwirq
= ICU_TINT_EXTRACT_HWIRQ(hwirq
);
386 if (hwirq
< ICU_TINT_START
)
390 if (hwirq
> (ICU_NUM_IRQ
- 1))
393 ret
= irq_domain_set_hwirq_and_chip(domain
, virq
, hwirq
, priv
->irqchip
,
394 (void *)(uintptr_t)tint
);
398 return irq_domain_alloc_irqs_parent(domain
, virq
, nr_irqs
, &priv
->fwspec
[hwirq
]);
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
,
407 static int rzv2h_icu_parse_interrupts(struct rzv2h_icu_priv
*priv
, struct device_node
*np
)
409 struct of_phandle_args map
;
413 for (i
= 0; i
< ICU_NUM_IRQ
; i
++) {
414 ret
= of_irq_parse_one(np
, i
, &map
);
418 of_phandle_args_to_fwspec(np
, map
.args
, map
.args_count
, &priv
->fwspec
[i
]);
424 static int rzv2h_icu_init(struct device_node
*node
, struct device_node
*parent
)
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
;
432 pdev
= of_find_device_by_node(node
);
436 parent_domain
= irq_find_host(parent
);
437 if (!parent_domain
) {
438 dev_err(&pdev
->dev
, "cannot find parent domain\n");
443 rzv2h_icu_data
= devm_kzalloc(&pdev
->dev
, sizeof(*rzv2h_icu_data
), GFP_KERNEL
);
444 if (!rzv2h_icu_data
) {
449 rzv2h_icu_data
->irqchip
= &rzv2h_icu_chip
;
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
);
457 ret
= rzv2h_icu_parse_interrupts(rzv2h_icu_data
, node
);
459 dev_err(&pdev
->dev
, "cannot parse interrupts: %d\n", ret
);
463 resetn
= devm_reset_control_get_exclusive(&pdev
->dev
, NULL
);
464 if (IS_ERR(resetn
)) {
465 ret
= PTR_ERR(resetn
);
469 ret
= reset_control_deassert(resetn
);
471 dev_err(&pdev
->dev
, "failed to deassert resetn pin, %d\n", ret
);
475 pm_runtime_enable(&pdev
->dev
);
476 ret
= pm_runtime_resume_and_get(&pdev
->dev
);
478 dev_err(&pdev
->dev
, "pm_runtime_resume_and_get failed: %d\n", ret
);
482 raw_spin_lock_init(&rzv2h_icu_data
->lock
);
484 irq_domain
= irq_domain_add_hierarchy(parent_domain
, 0, ICU_NUM_IRQ
, node
,
485 &rzv2h_icu_domain_ops
, rzv2h_icu_data
);
487 dev_err(&pdev
->dev
, "failed to add irq domain\n");
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.
499 pm_runtime_put(&pdev
->dev
);
501 pm_runtime_disable(&pdev
->dev
);
502 reset_control_assert(resetn
);
504 put_device(&pdev
->dev
);
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 <fabrizio.castro.jz@renesas.com>");
513 MODULE_DESCRIPTION("Renesas RZ/V2H(P) ICU Driver");