Search code examples
linux-device-driverbootdevice-tree

In device tree, a node's interrupts output cell size is 1 but its interrupt-parent seems to have #interrupt-cells = 3. Why?


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?


Solution

  • 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:

    • 2 address cells for the device (#address-cells = <2>)
    • 1 interrupt cell for the device (#interrupt-cells = <1>)
    • 1 cell containing a phandle for the upstream interrupt controller
    • 2 address cells for the upstream interrupt controller (#address-cells = <2>)
    • 3 interrupt cells for the upstream interrupt controller (#interrupt-cells = <3>)

    The interrupt-map-mask property consists of 3 cells, comprising:

    • 2 address mask cells to match against the device reg property (#address-cells = <2>)
    • 1 interrupt mask cell to match against the device 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".