1 /*
2  * Copyright (c) 2018 Intel Corporation.
3  * Copyright (c) 2024 Meta.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/sw_isr_table.h>
9 #include <zephyr/sys/util.h>
10 
11 /**
12  * @file
13  * @brief This file houses the deprecated legacy macros-generated multi-level interrupt lookup
14  * table code, compiled when `CONFIG_LEGACY_MULTI_LEVEL_TABLE_GENERATION` is enabled.
15  */
16 
17 /*
18  * Insert code if the node_id is an interrupt controller
19  */
20 #define Z_IF_DT_IS_INTC(node_id, code)                                                             \
21 	IF_ENABLED(DT_NODE_HAS_PROP(node_id, interrupt_controller), (code))
22 
23 /*
24  * Expands to node_id if its IRQN is equal to `_irq`, nothing otherwise
25  * This only works for `_irq` between 0 & 4095, see `IS_EQ`
26  */
27 #define Z_IF_DT_INTC_IRQN_EQ(node_id, _irq) IF_ENABLED(IS_EQ(DT_IRQ(node_id, irq), _irq), (node_id))
28 
29 /*
30  * Expands to node_id if it's an interrupt controller & its IRQN is `irq`, or nothing otherwise
31  */
32 #define Z_DT_INTC_GET_IRQN(node_id, _irq)                                                          \
33 	Z_IF_DT_IS_INTC(node_id, Z_IF_DT_INTC_IRQN_EQ(node_id, _irq))
34 
35 /**
36  * Loop through child of "/soc" and get root interrupt controllers with `_irq` as IRQN,
37  * this assumes only one device has the IRQN
38  * @param _irq irq number
39  * @return node_id(s) that has the `_irq` number, or empty if none of them has the `_irq`
40  */
41 #define INTC_DT_IRQN_GET(_irq)                                                                     \
42 	DT_FOREACH_CHILD_STATUS_OKAY_VARGS(DT_PATH(soc), Z_DT_INTC_GET_IRQN, _irq)
43 
44 #define INIT_IRQ_PARENT_OFFSET_2ND(n, d, i, o)                                                     \
45 	IRQ_PARENT_ENTRY_DEFINE(intc_l2_##n, DEVICE_DT_GET_OR_NULL(d), i, o, 2)
46 
47 #define IRQ_INDEX_TO_OFFSET(i, base) (base + i * CONFIG_MAX_IRQ_PER_AGGREGATOR)
48 
49 #define CAT_2ND_LVL_LIST(i, base)                                                                  \
50 	INIT_IRQ_PARENT_OFFSET_2ND(i, INTC_DT_IRQN_GET(CONFIG_2ND_LVL_INTR_0##i##_OFFSET),         \
51 				   CONFIG_2ND_LVL_INTR_0##i##_OFFSET,                              \
52 				   IRQ_INDEX_TO_OFFSET(i, base))
53 
54 LISTIFY(CONFIG_NUM_2ND_LEVEL_AGGREGATORS, CAT_2ND_LVL_LIST, (;), CONFIG_2ND_LVL_ISR_TBL_OFFSET);
55 
56 #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
57 
58 BUILD_ASSERT((CONFIG_NUM_3RD_LEVEL_AGGREGATORS * CONFIG_MAX_IRQ_PER_AGGREGATOR) <=
59 		     BIT(CONFIG_3RD_LEVEL_INTERRUPT_BITS),
60 	     "L3 bits not enough to cover the number of L3 IRQs");
61 
62 #define INIT_IRQ_PARENT_OFFSET_3RD(n, d, i, o)                                                     \
63 	IRQ_PARENT_ENTRY_DEFINE(intc_l3_##n, DEVICE_DT_GET_OR_NULL(d), i, o, 3)
64 
65 #define CAT_3RD_LVL_LIST(i, base)                                                                  \
66 	INIT_IRQ_PARENT_OFFSET_3RD(i, INTC_DT_IRQN_GET(CONFIG_3RD_LVL_INTR_0##i##_OFFSET),         \
67 				   CONFIG_3RD_LVL_INTR_0##i##_OFFSET,                              \
68 				   IRQ_INDEX_TO_OFFSET(i, base))
69 
70 LISTIFY(CONFIG_NUM_3RD_LEVEL_AGGREGATORS, CAT_3RD_LVL_LIST, (;), CONFIG_3RD_LVL_ISR_TBL_OFFSET);
71 
72 #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
73