xref: /linux/drivers/irqchip/irq-renesas-rzv2h.c (revision 7f71507851fc7764b36a3221839607d3a45c2025)
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 <fabrizio.castro.jz@renesas.com>
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 
97 static inline struct rzv2h_icu_priv *irq_data_to_priv(struct irq_data *data)
98 {
99 	return data->domain->host_data;
100 }
101 
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 
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 
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 
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 
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 
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 
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 
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 
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 
305 	titsr_k = ICU_TITSR_K(tint_nr);
306 	titsel_n = ICU_TITSR_TITSEL_N(tint_nr);
307 	tien = ICU_TSSR_TIEN(titsel_n);
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 
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 
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 
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 
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 <fabrizio.castro.jz@renesas.com>");
513 MODULE_DESCRIPTION("Renesas RZ/V2H(P) ICU Driver");
514