1 /*
2  * Copyright 2023 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Driver for NXP's IRQ_STEER IP.
10  *
11  * Below you may find some useful information that will help you better understand how the
12  * driver works. The ">" sign is used to mark ideas that are considered important and should
13  * be taken note of.
14  *
15  * 1) What is the IRQ_STEER IP?
16  *	- in Zephyr terminology, the IRQ_STEER can be considered an interrupt aggregator. As such,
17  *	its main goal is to multiplex multiple interrupt lines into a single/multiple ones.
18  *
19  * 2) How does the IRQ_STEER IP work?
20  *	- below you may find a diagram meant to give you an intuition regarding the IP's structure
21  *	and how it works (all of the information below is applicable to i.MX8MP but it can be
22  *	extended to any NXP SoC using the IRQ_STEER IP):
23  *
24  *                 SYSTEM_INTID[0:159]
25  *                        |
26  *      MASK[0:4]------   |
27  *                    |   |
28  *                  +------+
29  *                  |      |
30  *                  |32 AND|
31  *                  |      |
32  *                  +------+
33  *                        |
34  *      SET[0:4]------    |
35  *                   |    |
36  *                  +------+
37  *                  |      |
38  *                  |32 OR |
39  *                  |      |
40  *                  +------+
41  *                     |__________ STATUS[0:4]
42  *                     |
43  *                  +------+
44  *                  |GROUP |
45  *                  |  BY  |
46  *                  |  64  |
47  *                  +------+
48  *                   |  | |
49  *      _____________|  | |________________
50  *      |               |                 |
51  * MASTER_IN[0]    MASTER_IN[1]      MASTER_IN[2]
52  *      |               |                 |
53  *      |               |                 |
54  *      |_____________  |  _______________|
55  *                   |  | |
56  *                  +------+
57  *                  |      |
58  *                  | AND  | ---------- MINTDIS[0:2]
59  *                  |      |
60  *                  +------+
61  *                   |  | |
62  *      _____________|  | |________________
63  *      |               |                 |
64  * MASTER_OUT[0]  MASTER_OUT[1]      MASTER_OUT[2]
65  *
66  *	- initially, all SYSTEM_INTID are grouped by 32 => 5 groups.
67  *
68  *	> each of these groups is controlled by a MASK, SET and STATUS index as follows:
69  *
70  *		MASK/SET/STATUS[0] => SYSTEM_INTID[159:128]
71  *		MASK/SET/STATUS[1] => SYSTEM_INTID[127:96]
72  *		MASK/SET/STATUS[2] => SYSTEM_INTID[95:64]
73  *		MASK/SET/STATUS[3] => SYSTEM_INTID[63:32]
74  *		MASK/SET/STATUS[4] => SYSTEM_INTID[31:0]
75  *
76  *      > after that, all SYSTEM_INTID are grouped by 64 as follows:
77  *
78  *		SYSTEM_INTID[159:96] => MASTER_IN[2]
79  *              SYSTEM_INTID[95:32] => MASTER_IN[1]
80  *              SYSTEM_INTID[31:0] => MASTER_IN[0]
81  *
82  *      note: MASTER_IN[0] is only responsible for 32 interrupts
83  *
84  *      > the value of MASTER_IN[x] is obtained by OR'ing the input interrupt lines.
85  *
86  *      > the value of MASTER_OUT[x] is obtained by AND'ing MASTER_IN[x] with !MINTDIS[x].
87  *
88  *      - whenever a SYSTEM_INTID is asserted, its corresponding MASTER_OUT signal will also
89  *	be asserted, thus signaling the target processor.
90  *
91  *	> please note the difference between an IRQ_STEER channel and an IRQ_STEER master output.
92  *	An IRQ_STEER channel refers to an IRQ_STEER instance (e.g: the DSP uses IRQ_STEER channel
93  *	0 a.k.a instance 0). An IRQ_STEER channel has multiple master outputs. For example, in
94  *	the case of i.MX8MP each IRQ_STEER channel has 3 master outputs since an IRQ_STEER channel
95  *	routes 160 interrupts (32 for first master output, 64 for second master output, and 64 for
96  *	the third master output).
97  *
98  * 3) Using Zephyr's multi-level interrupt support
99  *	- since Zephyr supports organizing interrupts on multiple levels, we can use this to
100  *	separate the interrupts in 2 levels:
101  *		1) LEVEL 1 INTERRUPTS
102  *			- these are the interrupts that go directly to the processor (for example,
103  *			on i.MX8MP the MU can directly assert the DSP's interrupt line 7)
104  *
105  *		2) LEVEL 2 INTERRUPTS
106  *			- these interrupts go through IRQ_STEER and are signaled by a single
107  *			processor interrupt line.
108  *			- e.g: for i.MX8MP, INTID 34 (SDMA3) goes through IRQ_STEER and is signaled
109  *			to the DSP by INTID 20 which is a direct interrupt (or LEVEL 1 interrupt).
110  *
111  *	- the following diagram (1) shows the interrupt organization on i.MX8MP:
112  *	                                                        +------------+
113  *								|            |
114  *	      SYSTEM_INTID[31:0] ------ IRQ_STEER_MASTER_0 ----	| 19         |
115  *								|            |
116  *	      SYSTEM_INTID[95:32] ----- IRQ_STEER_MASTER_1 ----	| 20  DSP    |
117  *								|            |
118  *	      SYSTEM_INTID[159:96] ---- IRQ_STEER_MASTER_2 ----	| 21         |
119  *								|            |
120  *								+------------+
121  *
122  *	- as such, asserting a system interrupt will lead to asserting its corresponding DSP
123  *	interrupt line (for example, if system interrupt 34 is asserted, that would lead to
124  *	interrupt 20 being asserted)
125  *
126  *	- in the above diagram, SYSTEM_INTID[x] are LEVEL 2 interrupts, while 19, 20, and 21 are
127  *	LEVEL 1 interrupts.
128  *
129  *	- INTID 19 is the parent of SYSTEM_INTID[31:0] and so on.
130  *
131  *	> before going into how the INTIDs are encoded, we need to distinguish between 3 types of
132  *	INTIDs:
133  *		1) System INTIDs
134  *			- these are the values that can be found in NXP's TRMs for different
135  *			SoCs (usually they have the same IDs as the GIC SPIs)
136  *			- for example, INTID 34 is a system INTID for SDMA3 (i.MX8MP).
137  *
138  *		2) Zephyr INTIDs
139  *			- these are the Zephyr-specific encodings of the system INTIDs.
140  *			- these are used to encode multi-level interrupts (for more information
141  *			please see [1])
142  *			> if you need to register an interrupt dynamically, you need to use this
143  *			encoding when specifying the interrupt.
144  *
145  *		3) DTS INTIDs
146  *			- these are the encodings of the system INTIDs used in the DTS.
147  *			- all of these INTIDs are relative to IRQ_STEER's MASTER_OUTs.
148  *
149  *	> encoding an INTID:
150  *		1) SYSTEM INTID => ZEPHYR INTID
151  *			- the following steps need to be performed:
152  *
153  *				a) Find out which IRQ_STEER MASTER
154  *				is in charge of aggregating this interrupt.
155  *					* for instance, SYSTEM_INTID 34 (SDMA3 on i.MX8MP) is
156  *					aggregated by MASTER 1 as depicted in diagram (1).
157  *
158  *				b) After finding the MASTER aggregator, you need
159  *				to find the corresponding parent interrupt.
160  *					* for example, SYSTEM_INTID 34 (SDMA3 on i.MX8MP) is
161  *					aggregated by MASTER 1, which has the parent INTID 20
162  *					as depicted in diagram (1) => PARENT_INTID(34) = 20.
163  *
164  *				c) Find the INTID relative to the MASTER aggregator. This is done
165  *				by subtracting the number of interrupts each of the previous
166  *				master aggregators is in charge of. If the master aggregator is
167  *				MASTER 0 then RELATIVE_INTID=SYSTEM_INTID.
168  *					* for example, SYSTEM_ID 34 is aggregated by MASTER 1.
169  *					As such, we need to subtract 32 from 34 (because the
170  *					previous master - MASTER 0 - is in charge of aggregating
171  *					32 interrupts) => RELATIVE_INTID(34) = 2.
172  *
173  *					* generally speaking, RELATIVE_INTID can be computed using
174  *					the following formula (assuming SYSTEM_INTID belongs to
175  *					MASTER y):
176  *						RELATIVE_INTID(x) = x -
177  *							\sum{i=0}^{y - 1} GET_MASTER_INT_NUM(i)
178  *					where:
179  *						1) GET_MASTER_INT_NUM(x) computes the number of
180  *						interrupts master x aggregates
181  *						2) x is the system interrupt
182  *
183  *					* to make sure your computation is correct use the
184  *					following restriction:
185  *						0 <= RELATIVE_INTID(x) < GET_MASTER_INT_NUM(y)
186  *
187  *				d) To the obtained RELATIVE_INTID you need to add the value of 1,
188  *				left shift the result by the number of bits used to encode the
189  *				level 1 interrupts (see [1] for details) and OR the parent ID.
190  *					* for example, RELATIVE_INTID(34) = 2 (i.MX8MP),
191  *					PARENT_INTID(34) = 20 => ZEPHYR_INTID = ((2 + 1) << 8) | 20
192  *
193  *					* generally speaking, ZEPHYR_INTID can be computed using
194  *					the following formula:
195  *						ZEPHYR_INTID(x) = ((RELATIVE_INTID(x) + 1) <<
196  *						NUM_LVL1_BITS) | PARENT_INTID(x)
197  *					where:
198  *						1) RELATIVE_INTID(x) computes the relative INTID
199  *						of system interrupt x (step c).
200  *
201  *						2) NUM_LVL1_BITS is the number of bits used to
202  *						encode level 1 interrupts.
203  *
204  *						3) PARENT_INTID(x) computes the parent INTID of a
205  *						system interrupt x (step b)
206  *
207  *			- all of these steps are performed by to_zephyr_irq().
208  *			> for interrupts aggregated by MASTER 0 you may skip step c) as
209  *			RELATIVE_INTID(x) = x.
210  *
211  *		2) SYSTEM INTID => DTS INTID
212  *			- for this you just have to compute RELATIVE_INTID as described above in
213  *			step c).
214  *			- for example, if an IP uses INTID 34 you'd write its interrupts property
215  *			as follows (i.MX8MP):
216  *				interrupts = <&master1 2>;
217  *
218  * 4) Notes and comments
219  *	> PLEASE DON'T MISTAKE THE ZEPHYR MULTI-LEVEL INTERRUPT ORGANIZATION WITH THE XTENSA ONE.
220  *	THEY ARE DIFFERENT THINGS.
221  *
222  * [1]: https://docs.zephyrproject.org/latest/kernel/services/interrupts.html#multi-level-interrupt-handling
223  */
224 
225 #include <zephyr/device.h>
226 #include <zephyr/devicetree/interrupt_controller.h>
227 #include <zephyr/irq.h>
228 #include <fsl_irqsteer.h>
229 #include <zephyr/cache.h>
230 #include <zephyr/sw_isr_table.h>
231 #include <zephyr/logging/log.h>
232 #include <zephyr/pm/device_runtime.h>
233 #include <zephyr/pm/device.h>
234 
235 #include "sw_isr_common.h"
236 
237 LOG_MODULE_REGISTER(nxp_irqstr);
238 
239 /* used for driver binding */
240 #define DT_DRV_COMPAT nxp_irqsteer_intc
241 
242 /* macros used for DTS parsing */
243 #define _IRQSTEER_REGISTER_DISPATCHER(node_id)				\
244 	IRQ_CONNECT(DT_IRQN(node_id),					\
245 		    DT_IRQ(node_id, priority),				\
246 		    irqsteer_isr_dispatcher,				\
247 		    &dispatchers[DT_REG_ADDR(node_id)],			\
248 		    0)
249 
250 #define _IRQSTEER_DECLARE_DISPATCHER(node_id)				\
251 {									\
252 	.dev = DEVICE_DT_GET(DT_PARENT(node_id)),			\
253 	.master_index = DT_REG_ADDR(node_id),				\
254 	.irq = DT_IRQN(node_id),					\
255 }
256 
257 #define IRQSTEER_DECLARE_DISPATCHERS(parent_id)\
258 	DT_FOREACH_CHILD_STATUS_OKAY_SEP(parent_id, _IRQSTEER_DECLARE_DISPATCHER, (,))
259 
260 #define IRQSTEER_REGISTER_DISPATCHERS(parent_id)\
261 	DT_FOREACH_CHILD_STATUS_OKAY_SEP(parent_id, _IRQSTEER_REGISTER_DISPATCHER, (;))
262 
263 /* utility macros */
264 #define UINT_TO_IRQSTEER(x) ((IRQSTEER_Type *)(x))
265 #define DISPATCHER_REGMAP(disp) \
266 	(((const struct irqsteer_config *)disp->dev->config)->regmap_phys)
267 
268 struct irqsteer_config {
269 	uint32_t regmap_phys;
270 	uint32_t regmap_size;
271 	struct irqsteer_dispatcher *dispatchers;
272 };
273 
274 struct irqsteer_dispatcher {
275 	const struct device *dev;
276 	/* which set of interrupts is the dispatcher in charge of? */
277 	uint32_t master_index;
278 	/* which interrupt line is the dispatcher tied to? */
279 	uint32_t irq;
280 	/* reference count for all IRQs aggregated by dispatcher */
281 	uint8_t irq_refcnt[CONFIG_MAX_IRQ_PER_AGGREGATOR];
282 	/* dispatcher lock */
283 	struct k_spinlock lock;
284 	/* reference count for dispatcher */
285 	uint8_t refcnt;
286 };
287 
288 static struct irqsteer_dispatcher dispatchers[] = {
289 	IRQSTEER_DECLARE_DISPATCHERS(DT_NODELABEL(irqsteer))
290 };
291 
292 /* used to convert system INTID to zephyr INTID */
to_zephyr_irq(uint32_t regmap,uint32_t irq,struct irqsteer_dispatcher * dispatcher)293 static int to_zephyr_irq(uint32_t regmap, uint32_t irq,
294 			 struct irqsteer_dispatcher *dispatcher)
295 {
296 	int i, idx;
297 
298 	idx = irq;
299 
300 	for (i = dispatcher->master_index - 1; i >= 0; i--) {
301 		idx -= IRQSTEER_GetMasterIrqCount(UINT_TO_IRQSTEER(regmap), i);
302 	}
303 
304 	return irq_to_level_2(idx) | dispatcher->irq;
305 }
306 
307 /* used to convert master-relative INTID to system INTID */
to_system_irq(uint32_t regmap,int irq,int master_index)308 static int to_system_irq(uint32_t regmap, int irq, int master_index)
309 {
310 	int i;
311 
312 	for (i = master_index - 1; i >= 0; i--) {
313 		irq += IRQSTEER_GetMasterIrqCount(UINT_TO_IRQSTEER(regmap), i);
314 	}
315 
316 	return irq;
317 }
318 
319 /* used to convert zephyr INTID to system INTID */
from_zephyr_irq(uint32_t regmap,uint32_t irq,uint32_t master_index)320 static int from_zephyr_irq(uint32_t regmap, uint32_t irq, uint32_t master_index)
321 {
322 	int i, idx;
323 
324 	idx = irq;
325 
326 	for (i = 0; i < master_index; i++) {
327 		idx += IRQSTEER_GetMasterIrqCount(UINT_TO_IRQSTEER(regmap), i);
328 	}
329 
330 	return idx;
331 }
332 
_irqstr_disp_enable_disable(struct irqsteer_dispatcher * disp,bool enable)333 static void _irqstr_disp_enable_disable(struct irqsteer_dispatcher *disp,
334 					bool enable)
335 {
336 	uint32_t regmap = DISPATCHER_REGMAP(disp);
337 
338 	if (enable) {
339 		xtensa_irq_enable(XTENSA_IRQ_NUMBER(disp->irq));
340 
341 		IRQSTEER_EnableMasterInterrupt(UINT_TO_IRQSTEER(regmap), disp->irq);
342 	} else {
343 		IRQSTEER_DisableMasterInterrupt(UINT_TO_IRQSTEER(regmap), disp->irq);
344 
345 		xtensa_irq_disable(XTENSA_IRQ_NUMBER(disp->irq));
346 	}
347 }
348 
_irqstr_disp_get_unlocked(struct irqsteer_dispatcher * disp)349 static void _irqstr_disp_get_unlocked(struct irqsteer_dispatcher *disp)
350 {
351 	int ret;
352 
353 	if (disp->refcnt == UINT8_MAX) {
354 		LOG_WRN("disp for irq %d reference count reached limit", disp->irq);
355 		return;
356 	}
357 
358 	if (!disp->refcnt) {
359 		ret = pm_device_runtime_get(disp->dev);
360 		if (ret < 0) {
361 			LOG_ERR("failed to enable PM resources: %d", ret);
362 			return;
363 		}
364 
365 		_irqstr_disp_enable_disable(disp, true);
366 	}
367 
368 	disp->refcnt++;
369 
370 	LOG_DBG("get on disp for irq %d results in refcnt: %d",
371 		disp->irq, disp->refcnt);
372 }
373 
_irqstr_disp_put_unlocked(struct irqsteer_dispatcher * disp)374 static void _irqstr_disp_put_unlocked(struct irqsteer_dispatcher *disp)
375 {
376 	int ret;
377 
378 	if (!disp->refcnt) {
379 		LOG_WRN("disp for irq %d already put", disp->irq);
380 		return;
381 	}
382 
383 	disp->refcnt--;
384 
385 	if (!disp->refcnt) {
386 		_irqstr_disp_enable_disable(disp, false);
387 
388 		ret = pm_device_runtime_put(disp->dev);
389 		if (ret < 0) {
390 			LOG_ERR("failed to disable PM resources: %d", ret);
391 			return;
392 		}
393 	}
394 
395 	LOG_DBG("put on disp for irq %d results in refcnt: %d",
396 		disp->irq, disp->refcnt);
397 }
398 
_irqstr_enable_disable_irq(struct irqsteer_dispatcher * disp,uint32_t system_irq,bool enable)399 static void _irqstr_enable_disable_irq(struct irqsteer_dispatcher *disp,
400 				       uint32_t system_irq, bool enable)
401 {
402 	uint32_t regmap = DISPATCHER_REGMAP(disp);
403 
404 	if (enable) {
405 		IRQSTEER_EnableInterrupt(UINT_TO_IRQSTEER(regmap), system_irq);
406 	} else {
407 		IRQSTEER_DisableInterrupt(UINT_TO_IRQSTEER(regmap), system_irq);
408 	}
409 }
410 
irqstr_request_irq_unlocked(struct irqsteer_dispatcher * disp,uint32_t zephyr_irq)411 static void irqstr_request_irq_unlocked(struct irqsteer_dispatcher *disp,
412 					uint32_t zephyr_irq)
413 {
414 	uint32_t system_irq = from_zephyr_irq(DISPATCHER_REGMAP(disp),
415 					      zephyr_irq, disp->master_index);
416 
417 #ifndef CONFIG_SHARED_INTERRUPTS
418 	if (disp->irq_refcnt[zephyr_irq]) {
419 		LOG_WRN("irq %d already requested", system_irq);
420 		return;
421 	}
422 #endif /* CONFIG_SHARED_INTERRUPTS */
423 
424 	if (disp->irq_refcnt[zephyr_irq] == UINT8_MAX) {
425 		LOG_WRN("irq %d reference count reached limit", system_irq);
426 		return;
427 	}
428 
429 	if (!disp->irq_refcnt[zephyr_irq]) {
430 		_irqstr_disp_get_unlocked(disp);
431 		_irqstr_enable_disable_irq(disp, system_irq, true);
432 	}
433 
434 	disp->irq_refcnt[zephyr_irq]++;
435 
436 	LOG_DBG("requested irq %d has refcount %d",
437 		system_irq, disp->irq_refcnt[zephyr_irq]);
438 }
439 
irqstr_release_irq_unlocked(struct irqsteer_dispatcher * disp,uint32_t zephyr_irq)440 static void irqstr_release_irq_unlocked(struct irqsteer_dispatcher *disp,
441 					uint32_t zephyr_irq)
442 {
443 	uint32_t system_irq = from_zephyr_irq(DISPATCHER_REGMAP(disp),
444 					      zephyr_irq, disp->master_index);
445 
446 	if (!disp->irq_refcnt[zephyr_irq]) {
447 		LOG_WRN("irq %d already released", system_irq);
448 		return;
449 	}
450 
451 	disp->irq_refcnt[zephyr_irq]--;
452 
453 	if (!disp->irq_refcnt[zephyr_irq]) {
454 		_irqstr_enable_disable_irq(disp, system_irq, false);
455 		_irqstr_disp_put_unlocked(disp);
456 	}
457 
458 	LOG_DBG("released irq %d has refcount %d",
459 		system_irq, disp->irq_refcnt[zephyr_irq]);
460 }
461 
z_soc_irq_enable_disable(uint32_t irq,bool enable)462 void z_soc_irq_enable_disable(uint32_t irq, bool enable)
463 {
464 	uint32_t parent_irq;
465 	int i, level2_irq;
466 
467 	if (irq_get_level(irq) == 1) {
468 		/* LEVEL 1 interrupts are DSP direct */
469 		if (enable) {
470 			xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq));
471 		} else {
472 			xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq));
473 		}
474 		return;
475 	}
476 
477 	parent_irq = irq_parent_level_2(irq);
478 	level2_irq = irq_from_level_2(irq);
479 
480 	/* find dispatcher responsible for this interrupt */
481 	for (i = 0; i < ARRAY_SIZE(dispatchers); i++) {
482 		if (dispatchers[i].irq != parent_irq) {
483 			continue;
484 		}
485 
486 		K_SPINLOCK(&dispatchers[i].lock) {
487 			if (enable) {
488 				irqstr_request_irq_unlocked(&dispatchers[i], level2_irq);
489 			} else {
490 				irqstr_release_irq_unlocked(&dispatchers[i], level2_irq);
491 			}
492 		}
493 
494 		return;
495 	}
496 }
497 
z_soc_irq_enable(uint32_t irq)498 void z_soc_irq_enable(uint32_t irq)
499 {
500 	z_soc_irq_enable_disable(irq, true);
501 }
502 
z_soc_irq_disable(uint32_t irq)503 void z_soc_irq_disable(uint32_t irq)
504 {
505 	z_soc_irq_enable_disable(irq, false);
506 }
507 
z_soc_irq_is_enabled(unsigned int irq)508 int z_soc_irq_is_enabled(unsigned int irq)
509 {
510 	uint32_t parent_irq;
511 	int i;
512 	const struct irqsteer_config *cfg;
513 	bool enabled;
514 
515 	if (irq_get_level(irq) == 1) {
516 		/* LEVEL 1 interrupts are DSP direct */
517 		return xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq));
518 	}
519 
520 	parent_irq = irq_parent_level_2(irq);
521 	enabled = false;
522 
523 	/* find dispatcher responsible for this interrupt */
524 	for (i = 0; i < ARRAY_SIZE(dispatchers); i++) {
525 		if (dispatchers[i].irq != parent_irq) {
526 			continue;
527 		}
528 
529 		cfg = dispatchers[i].dev->config;
530 
531 		K_SPINLOCK(&dispatchers[i].lock) {
532 			enabled = dispatchers[i].irq_refcnt[irq_from_level_2(irq)];
533 		}
534 
535 		return enabled;
536 	}
537 
538 	return false;
539 }
540 
541 
irqsteer_isr_dispatcher(const void * data)542 static void irqsteer_isr_dispatcher(const void *data)
543 {
544 	struct irqsteer_dispatcher *dispatcher;
545 	const struct irqsteer_config *cfg;
546 	uint32_t table_idx;
547 	int system_irq, zephyr_irq, i;
548 	uint64_t status;
549 
550 	dispatcher = (struct irqsteer_dispatcher *)data;
551 	cfg = dispatcher->dev->config;
552 
553 	/* fetch master interrupts status */
554 	status = IRQSTEER_GetMasterInterruptsStatus(UINT_TO_IRQSTEER(cfg->regmap_phys),
555 						    dispatcher->master_index);
556 
557 	for (i = 0; status; i++) {
558 		/* if bit 0 is set then that means relative INTID i is asserted */
559 		if (status & 1) {
560 			/* convert master-relative INTID to a system INTID */
561 			system_irq = to_system_irq(cfg->regmap_phys, i,
562 						   dispatcher->master_index);
563 
564 			/* convert system INTID to a Zephyr INTID */
565 			zephyr_irq = to_zephyr_irq(cfg->regmap_phys, system_irq, dispatcher);
566 
567 			/* compute index in the SW ISR table */
568 			table_idx = z_get_sw_isr_table_idx(zephyr_irq);
569 
570 			/* call child's ISR */
571 			_sw_isr_table[table_idx].isr(_sw_isr_table[table_idx].arg);
572 		}
573 
574 		status >>= 1;
575 	}
576 }
577 
irqstr_pm_action(const struct device * dev,enum pm_device_action action)578 __maybe_unused static int irqstr_pm_action(const struct device *dev,
579 					   enum pm_device_action action)
580 {
581 	/* nothing to be done here */
582 	return 0;
583 }
584 
irqsteer_init(const struct device * dev)585 static int irqsteer_init(const struct device *dev)
586 {
587 	IRQSTEER_REGISTER_DISPATCHERS(DT_NODELABEL(irqsteer));
588 
589 	return pm_device_runtime_enable(dev);
590 }
591 
592 
593 /* TODO: do we need to add support for MMU-based SoCs? */
594 static struct irqsteer_config irqsteer_config = {
595 	.regmap_phys = DT_REG_ADDR(DT_NODELABEL(irqsteer)),
596 	.regmap_size = DT_REG_SIZE(DT_NODELABEL(irqsteer)),
597 	.dispatchers = dispatchers,
598 };
599 
600 /* assumption: only 1 IRQ_STEER instance */
601 PM_DEVICE_DT_INST_DEFINE(0, irqstr_pm_action);
602 DEVICE_DT_INST_DEFINE(0,
603 		      &irqsteer_init,
604 		      PM_DEVICE_DT_INST_GET(0),
605 		      NULL, &irqsteer_config,
606 		      PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY,
607 		      NULL);
608 
609 #define NXP_IRQSTEER_MASTER_IRQ_ENTRY_DEF(node_id)                                                 \
610 	IRQ_PARENT_ENTRY_DEFINE(CONCAT(nxp_irqsteer_master_, DT_NODE_CHILD_IDX(node_id)), NULL,    \
611 				DT_IRQN(node_id), INTC_CHILD_ISR_TBL_OFFSET(node_id),              \
612 				DT_INTC_GET_AGGREGATOR_LEVEL(node_id));
613 
614 DT_INST_FOREACH_CHILD_STATUS_OKAY(0, NXP_IRQSTEER_MASTER_IRQ_ENTRY_DEF);
615