I'm making a dts file by modifying an existing one and it's still hard to understand device tree syntax and meaning with digging the bindings documents. Here is another one I can't understand. Please help me..
In linux-5.15 source, I see in arch/arm64/boot/dts/arm/fvp-base-revc.dts (showing parts),
#include "rtsm_ve-motherboard.dtsi"
#include "rtsm_ve-motherboard-rs2.dtsi"
/ {
model = "FVP Base RevC";
compatible = "arm,fvp-base-revc", "arm,vexpress";
interrupt-parent = <&gic>; <== see this
#address-cells = <2>;
#size-cells = <2>;
...
gic: interrupt-controller@2f000000 {
compatible = "arm,gic-v3";
#interrupt-cells = <3>; <=== see this
#address-cells = <2>;
#size-cells = <2>;
ranges;
interrupt-controller;
....
};
timer {
compatible = "arm,armv8-timer";
interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>, <== see these lines (3 values per cell)
<GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
<GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
<GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
};
So because gic
has #incterrupt-cells = <3>, (for interrupt type, number and flag), the timer
node generating 4 interrupts has 3 values for each interrupts cell. But in file rtsm_ve-motherboard.dtsi
which is included earlier, I see this lines.
v2m_serial0: serial@90000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x090000 0x1000>;
interrupts = <5>; <== see this, (1 value per cell, why?)
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
clock-names = "uartclk", "apb_pclk";
};
v2m_serial1: serial@a0000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x0a0000 0x1000>;
interrupts = <6>; <== see this, (1 value per cell, why?)
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
clock-names = "uartclk", "apb_pclk";
};
Why does the interrupts value has only 1 cell here? (interrupts = <6>) I couldn't find any interrupt controller specifying #interrupt-cells = 1
in the binding documents or existing dts files.
Why does v2m_serial0 node has only one value for interrupts
value?
The path to v2m_serial0: serial@90000
is:
/bus@8000000/motherboard-bus@8000000/iofpga-bus@300000000/serial@90000
Going up to towards the root, the first node with an #interrupt-cells
property is bus@8000000
. The bus@8000000
node is partly defined in the "rtsm_ve-motherboard.dtsi" file:
bus@8000000 {
compatible = "simple-bus";
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0x8000000 0 0x8000000 0x18000000>;
motherboard-bus@8000000 {
…
The node has additional material defined in the "rtsm_ve-motherboard-rs2.dtsi", which is not important right now, and in the "fvp-base-revc.dts" file, which contains the #interrupt-cells
property:
bus@8000000 {
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 63>;
interrupt-map = <0 0 0 &gic 0 0 GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
<0 0 1 &gic 0 0 GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
<0 0 2 &gic 0 0 GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
<0 0 3 &gic 0 0 GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
<0 0 4 &gic 0 0 GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
<0 0 5 &gic 0 0 GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
<0 0 6 &gic 0 0 GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
…
<0 0 43 &gic 0 0 GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
<0 0 44 &gic 0 0 GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
};
The #interrupt-cells
property has value 1, so that is why the interrupts
properties in the child nodes have one cell per interrupt.
The interrupt-map
property is mapping the one-cell interrupt values to interrupts in the &gic
interrupt controller. Each mapping element above consists of 9 cells, comprising of:
#address-cells = <2>
)#interrupt-cells = <1>
)#address-cells = <2>
)#interrupt-cells = <3>
)The interrupt-map-mask
property consists of 3 cells, comprising:
reg
property (#address-cells = <2>
)interrupt
property (#interrupt-cells = <1>
)The v2m_serial0: serial@90000
node has the following reg
and interrupts
properties:
reg = <0x090000 0x1000>;
interrupts = <5>;
The combined address and interrupts cell values are <0x090000 0x1000 5>
. When AND-ed with the interrupt-map-mask
property value <0 0 63>
, the result is <0 0 5>
, which matches the interrupt mapping element <0 0 5 &gic 0 0 GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>
. Therefore, the device's interrupts
property value is mapped to the <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>
interrupt value for the &gic
interrupt controller.
The interrupt map parsing and matching is done by of_irq_parse_raw()
in "drivers/of/irq.c".