devicetree: encode multi-level interrupt number in C devicetree magic
The multi-level encoding of the interrupt number currently happens in the `gen_defines.py`, which is called in the `dts.cmake` module after `kconfig.cmake`. However, the number of bits used by each level is defined in Kconfig and this means that `gen_defines.py` will not be able to get that information during build. To fix this, do the multi-level encoding in C devicetree macro magic instead of the python script. This ticks one of a long-standing TODO item from the `gen_defines.py`. Signed-off-by: Yong Cong Sin <ycsin@meta.com>
This commit is contained in:
parent
d7302f417e
commit
df2c0681d3
4 changed files with 85 additions and 21 deletions
|
@ -377,7 +377,7 @@ DEVICE_DT_INST_DEFINE(0,
|
|||
&gpio_sifive_driver);
|
||||
|
||||
#define IRQ_INIT(n) \
|
||||
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, n, irq), \
|
||||
IRQ_CONNECT(DT_INST_IRQN_BY_IDX(0, n), \
|
||||
DT_INST_IRQ_BY_IDX(0, n, priority), \
|
||||
gpio_sifive_irq_handler, \
|
||||
DEVICE_DT_INST_GET(0), \
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#define DEVICETREE_H
|
||||
|
||||
#include <devicetree_generated.h>
|
||||
#include <zephyr/irq_multilevel.h>
|
||||
|
||||
#if !defined(_LINKER) && !defined(_ASMLANGUAGE)
|
||||
#include <stdint.h>
|
||||
|
@ -2409,6 +2410,77 @@
|
|||
*/
|
||||
#define DT_IRQ(node_id, cell) DT_IRQ_BY_IDX(node_id, 0, cell)
|
||||
|
||||
/**
|
||||
* @cond INTERNAL_HIDDEN
|
||||
*/
|
||||
|
||||
/* DT helper macro to get interrupt-parent node */
|
||||
#define DT_PARENT_INTC_INTERNAL(node_id) DT_PROP(node_id, interrupt_parent)
|
||||
/* DT helper macro to get the node's interrupt grandparent node */
|
||||
#define DT_GPARENT_INTC_INTERNAL(node_id) DT_PARENT_INTC_INTERNAL(DT_PARENT_INTC_INTERNAL(node_id))
|
||||
/* DT helper macro to check if a node is an interrupt controller */
|
||||
#define DT_IS_INTC_INTERNAL(node_id) DT_NODE_HAS_PROP(node_id, interrupt_controller)
|
||||
/* DT helper macro to check if the node has a parent interrupt controller */
|
||||
#define DT_HAS_PARENT_INTC_INTERNAL(node_id) \
|
||||
/* node has `interrupt-parent`? */ \
|
||||
IF_ENABLED(DT_NODE_HAS_PROP(node_id, interrupt_parent), \
|
||||
/* `interrupt-parent` node is an interrupt controller? */ \
|
||||
(IF_ENABLED(DT_IS_INTC_INTERNAL(DT_PARENT_INTC_INTERNAL(node_id)), \
|
||||
/* `interrupt-parent` node has interrupt cell(s) ? 1 : 0 */ \
|
||||
(COND_CODE_0(DT_NUM_IRQS(DT_PARENT_INTC_INTERNAL(node_id)), (0), \
|
||||
(1))))))
|
||||
/* DT helper macro to check if the node has a grandparent interrupt controller */
|
||||
#define DT_HAS_GPARENT_INTC_INTERNAL(node_id) \
|
||||
IF_ENABLED(DT_HAS_PARENT_INTC_INTERNAL(node_id), \
|
||||
(DT_HAS_PARENT_INTC_INTERNAL(DT_PARENT_INTC_INTERNAL(node_id))))
|
||||
|
||||
/**
|
||||
* DT helper macro to get the as-seen interrupt number in devicetree,
|
||||
* or ARM GIC IRQ encoded output from `gen_defines.py`
|
||||
*/
|
||||
#define DT_IRQN_BY_IDX_INTERNAL(node_id, idx) DT_IRQ_BY_IDX(node_id, idx, irq)
|
||||
|
||||
/* DT helper macro to get the node's parent intc's (only) irq number */
|
||||
#define DT_PARENT_INTC_IRQN_INTERNAL(node_id) DT_IRQ(DT_PARENT_INTC_INTERNAL(node_id), irq)
|
||||
/* DT helper macro to get the node's grandparent intc's (only) irq number */
|
||||
#define DT_GPARENT_INTC_IRQN_INTERNAL(node_id) DT_IRQ(DT_GPARENT_INTC_INTERNAL(node_id), irq)
|
||||
|
||||
/* DT helper macro to encode a node's IRQN to level 2 according to the multi-level scheme */
|
||||
#define DT_IRQN_L2_INTERNAL(node_id, idx) \
|
||||
(IRQ_TO_L2(DT_IRQN_BY_IDX_INTERNAL(node_id, idx)) | \
|
||||
DT_PARENT_INTC_IRQN_INTERNAL(node_id))
|
||||
/* DT helper macro to encode a node's IRQN to level 3 according to the multi-level scheme */
|
||||
#define DT_IRQN_L3_INTERNAL(node_id, idx) \
|
||||
(IRQ_TO_L3(DT_IRQN_BY_IDX_INTERNAL(node_id, idx)) | \
|
||||
IRQ_TO_L2(DT_PARENT_INTC_IRQN_INTERNAL(node_id)) | \
|
||||
DT_GPARENT_INTC_IRQN_INTERNAL(node_id))
|
||||
/**
|
||||
* DT helper macro to encode a node's interrupt number according to the Zephyr's multi-level scheme
|
||||
* See doc/kernel/services/interrupts.rst for details
|
||||
*/
|
||||
#define DT_MULTI_LEVEL_IRQN_INTERNAL(node_id, idx) \
|
||||
COND_CODE_1(DT_HAS_GPARENT_INTC_INTERNAL(node_id), (DT_IRQN_L3_INTERNAL(node_id, idx)), \
|
||||
(COND_CODE_1(DT_HAS_PARENT_INTC_INTERNAL(node_id), \
|
||||
(DT_IRQN_L2_INTERNAL(node_id, idx)), \
|
||||
(DT_IRQN_BY_IDX_INTERNAL(node_id, idx)))))
|
||||
|
||||
/**
|
||||
* INTERNAL_HIDDEN @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Get the node's Zephyr interrupt number at index
|
||||
* If @kconfig{CONFIG_MULTI_LEVEL_INTERRUPTS} is enabled, the interrupt number at index will be
|
||||
* multi-level encoded
|
||||
* @param node_id node identifier
|
||||
* @param idx logical index into the interrupt specifier array
|
||||
* @return the Zephyr interrupt number
|
||||
*/
|
||||
#define DT_IRQN_BY_IDX(node_id, idx) \
|
||||
COND_CODE_1(IS_ENABLED(CONFIG_MULTI_LEVEL_INTERRUPTS), \
|
||||
(DT_MULTI_LEVEL_IRQN_INTERNAL(node_id, idx)), \
|
||||
(DT_IRQN_BY_IDX_INTERNAL(node_id, idx)))
|
||||
|
||||
/**
|
||||
* @brief Get a node's (only) irq number
|
||||
*
|
||||
|
@ -2419,7 +2491,7 @@
|
|||
* @param node_id node identifier
|
||||
* @return the interrupt number for the node's only interrupt
|
||||
*/
|
||||
#define DT_IRQN(node_id) DT_IRQ(node_id, irq)
|
||||
#define DT_IRQN(node_id) DT_IRQN_BY_IDX(node_id, 0)
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
@ -3825,7 +3897,15 @@
|
|||
* @param inst instance number
|
||||
* @return the interrupt number for the node's only interrupt
|
||||
*/
|
||||
#define DT_INST_IRQN(inst) DT_INST_IRQ(inst, irq)
|
||||
#define DT_INST_IRQN(inst) DT_IRQN(DT_DRV_INST(inst))
|
||||
|
||||
/**
|
||||
* @brief Get a `DT_DRV_COMPAT`'s irq number at index
|
||||
* @param inst instance number
|
||||
* @param idx logical index into the interrupt specifier array
|
||||
* @return the interrupt number for the node's idx-th interrupt
|
||||
*/
|
||||
#define DT_INST_IRQN_BY_IDX(inst, idx) DT_IRQN_BY_IDX(DT_DRV_INST(inst), idx)
|
||||
|
||||
/**
|
||||
* @brief Get a `DT_DRV_COMPAT`'s bus node identifier
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#ifndef _ASMLANGUAGE
|
||||
#include <zephyr/sys/util_macro.h>
|
||||
#include <zephyr/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
@ -436,8 +436,7 @@ def write_interrupts(node):
|
|||
# interrupts property: we have some hard-coded logic for interrupt
|
||||
# mapping here.
|
||||
#
|
||||
# TODO: can we push map_arm_gic_irq_type() and
|
||||
# encode_zephyr_multi_level_irq() out of Python and into C with
|
||||
# TODO: can we push map_arm_gic_irq_type() out of Python and into C with
|
||||
# macro magic in devicetree.h?
|
||||
|
||||
def map_arm_gic_irq_type(irq, irq_num):
|
||||
|
@ -453,21 +452,6 @@ def write_interrupts(node):
|
|||
return irq_num + 16
|
||||
err(f"Invalid interrupt type specified for {irq!r}")
|
||||
|
||||
def encode_zephyr_multi_level_irq(irq, irq_num):
|
||||
# See doc/kernel/services/interrupts.rst for details
|
||||
# on how this encoding works
|
||||
|
||||
irq_ctrl = irq.controller
|
||||
# Look for interrupt controller parent until we have none
|
||||
while irq_ctrl.interrupts:
|
||||
irq_num = (irq_num + 1) << 8
|
||||
if "irq" not in irq_ctrl.interrupts[0].data:
|
||||
err(f"Expected binding for {irq_ctrl!r} to have 'irq' in "
|
||||
"interrupt-cells")
|
||||
irq_num |= irq_ctrl.interrupts[0].data["irq"]
|
||||
irq_ctrl = irq_ctrl.interrupts[0].controller
|
||||
return irq_num
|
||||
|
||||
idx_vals = []
|
||||
name_vals = []
|
||||
path_id = node.z_path_id
|
||||
|
@ -482,7 +466,6 @@ def write_interrupts(node):
|
|||
if cell_name == "irq":
|
||||
if "arm,gic" in irq.controller.compats:
|
||||
cell_value = map_arm_gic_irq_type(irq, cell_value)
|
||||
cell_value = encode_zephyr_multi_level_irq(irq, cell_value)
|
||||
|
||||
idx_vals.append((f"{path_id}_IRQ_IDX_{i}_EXISTS", 1))
|
||||
idx_macro = f"{path_id}_IRQ_IDX_{i}_VAL_{name}"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue