Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'irq-drivers-2026-02-09' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq chip driver updates from Thomas Gleixner:

- Add support for the Renesas RZ/V2N SoC

- Add a new driver for the Renesas RZ/[TN]2H SoCs

- Preserve the register state of the RISCV APLIC interrupt controller
accross suspend/resume

- Reinitialize the RISCV IMSIC registers after suspend/resume

- Make the various Loongson interrupt chip drivers 32/64-bit aware

- Handle the number of hardware interrupts in the SIFIVE PLIC driver
correctly

The hardware interrupt 0 is reserved which resulted in inconsistent
accounting. That went unnoticed as the off by one is only noticable
when the number of device interrupts is a multiple of 32

- The usual device tree updates, cleanups and improvements all over the
place

* tag 'irq-drivers-2026-02-09' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (24 commits)
irqchip/gic-v5: Fix spelling mistake "ouside" -> "outside"
dt-bindings: interrupt-controller: sifive,plic: Clarify the riscv,ndev meaning in PLIC
irqchip/sifive-plic: Handle number of hardware interrupts correctly
irqchip/aspeed-scu-ic: Remove unused variable mask
irqchip/ti-sci-intr: Allow parsing interrupt-types per-line
dt-bindings: interrupt-controller: ti,sci-intr: Per-line interrupt-types
irqchip/renesas-rzv2h: Add suspend/resume support
irqchip/aslint-sswi: Fix error check of of_io_request_and_map() result
irqchip: Allow LoongArch irqchip drivers on both 32BIT/64BIT
irqchip/loongson-pch-pic: Adjust irqchip driver for 32BIT/64BIT
irqchip/loongson-pch-msi: Adjust irqchip driver for 32BIT/64BIT
irqchip/loongson-htvec: Adjust irqchip driver for 32BIT/64BIT
irqchip/loongson-eiointc: Adjust irqchip driver for 32BIT/64BIT
irqchip/loongson-liointc: Adjust irqchip driver for 32BIT/64BIT
irqchip/loongarch-avec: Adjust irqchip driver for 32BIT/64BIT
irqchip/riscv-aplic: Preserve APLIC states across suspend/resume
irqchip/riscv-imsic: Add a CPU pm notifier to restore the IMSIC on exit
arm64: dts: renesas: r9a09g087: Add ICU support
arm64: dts: renesas: r9a09g077: Add ICU support
irqchip: Add RZ/{T2H,N2H} Interrupt Controller (ICU) driver
...

+1172 -120
+236
Documentation/devicetree/bindings/interrupt-controller/renesas,r9a09g077-icu.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/interrupt-controller/renesas,r9a09g077-icu.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Renesas RZ/{T2H,N2H} Interrupt Controller 8 + 9 + maintainers: 10 + - Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com> 11 + 12 + allOf: 13 + - $ref: /schemas/interrupt-controller.yaml# 14 + 15 + description: 16 + The Interrupt Controller (ICU) handles software-triggered interrupts 17 + (INTCPU), external interrupts (IRQ and SEI), error interrupts and DMAC 18 + requests. 19 + 20 + properties: 21 + compatible: 22 + oneOf: 23 + - const: renesas,r9a09g077-icu # RZ/T2H 24 + 25 + - items: 26 + - enum: 27 + - renesas,r9a09g087-icu # RZ/N2H 28 + - const: renesas,r9a09g077-icu 29 + 30 + reg: 31 + items: 32 + - description: Non-safety registers (INTCPU0-13, IRQ0-13) 33 + - description: Safety registers (INTCPU14-15, IRQ14-15, SEI) 34 + 35 + '#interrupt-cells': 36 + description: The first cell is the SPI number of the interrupt, as per user 37 + manual. The second cell is used to specify the flag. 38 + const: 2 39 + 40 + '#address-cells': 41 + const: 0 42 + 43 + interrupt-controller: true 44 + 45 + interrupts: 46 + items: 47 + - description: Software interrupt 0 48 + - description: Software interrupt 1 49 + - description: Software interrupt 2 50 + - description: Software interrupt 3 51 + - description: Software interrupt 4 52 + - description: Software interrupt 5 53 + - description: Software interrupt 6 54 + - description: Software interrupt 7 55 + - description: Software interrupt 8 56 + - description: Software interrupt 9 57 + - description: Software interrupt 10 58 + - description: Software interrupt 11 59 + - description: Software interrupt 12 60 + - description: Software interrupt 13 61 + - description: Software interrupt 14 62 + - description: Software interrupt 15 63 + - description: External pin interrupt 0 64 + - description: External pin interrupt 1 65 + - description: External pin interrupt 2 66 + - description: External pin interrupt 3 67 + - description: External pin interrupt 4 68 + - description: External pin interrupt 5 69 + - description: External pin interrupt 6 70 + - description: External pin interrupt 7 71 + - description: External pin interrupt 8 72 + - description: External pin interrupt 9 73 + - description: External pin interrupt 10 74 + - description: External pin interrupt 11 75 + - description: External pin interrupt 12 76 + - description: External pin interrupt 13 77 + - description: External pin interrupt 14 78 + - description: External pin interrupt 15 79 + - description: System error interrupt 80 + - description: Cortex-A55 error event 0 81 + - description: Cortex-A55 error event 1 82 + - description: Cortex-R52 CPU 0 error event 0 83 + - description: Cortex-R52 CPU 0 error event 1 84 + - description: Cortex-R52 CPU 1 error event 0 85 + - description: Cortex-R52 CPU 1 error event 1 86 + - description: Peripherals error event 0 87 + - description: Peripherals error event 1 88 + - description: DSMIF error event 0 89 + - description: DSMIF error event 1 90 + - description: ENCIF error event 0 91 + - description: ENCIF error event 1 92 + 93 + interrupt-names: 94 + items: 95 + - const: intcpu0 96 + - const: intcpu1 97 + - const: intcpu2 98 + - const: intcpu3 99 + - const: intcpu4 100 + - const: intcpu5 101 + - const: intcpu6 102 + - const: intcpu7 103 + - const: intcpu8 104 + - const: intcpu9 105 + - const: intcpu10 106 + - const: intcpu11 107 + - const: intcpu12 108 + - const: intcpu13 109 + - const: intcpu14 110 + - const: intcpu15 111 + - const: irq0 112 + - const: irq1 113 + - const: irq2 114 + - const: irq3 115 + - const: irq4 116 + - const: irq5 117 + - const: irq6 118 + - const: irq7 119 + - const: irq8 120 + - const: irq9 121 + - const: irq10 122 + - const: irq11 123 + - const: irq12 124 + - const: irq13 125 + - const: irq14 126 + - const: irq15 127 + - const: sei 128 + - const: ca55-err0 129 + - const: ca55-err1 130 + - const: cr520-err0 131 + - const: cr520-err1 132 + - const: cr521-err0 133 + - const: cr521-err1 134 + - const: peri-err0 135 + - const: peri-err1 136 + - const: dsmif-err0 137 + - const: dsmif-err1 138 + - const: encif-err0 139 + - const: encif-err1 140 + 141 + clocks: 142 + maxItems: 1 143 + 144 + power-domains: 145 + maxItems: 1 146 + 147 + required: 148 + - compatible 149 + - reg 150 + - '#interrupt-cells' 151 + - '#address-cells' 152 + - interrupt-controller 153 + - interrupts 154 + - interrupt-names 155 + - clocks 156 + - power-domains 157 + 158 + unevaluatedProperties: false 159 + 160 + examples: 161 + - | 162 + #include <dt-bindings/interrupt-controller/arm-gic.h> 163 + #include <dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h> 164 + 165 + icu: interrupt-controller@802a0000 { 166 + compatible = "renesas,r9a09g077-icu"; 167 + reg = <0x802a0000 0x10000>, 168 + <0x812a0000 0x50>; 169 + #interrupt-cells = <2>; 170 + #address-cells = <0>; 171 + interrupt-controller; 172 + interrupts = <GIC_SPI 0 IRQ_TYPE_EDGE_RISING>, 173 + <GIC_SPI 1 IRQ_TYPE_EDGE_RISING>, 174 + <GIC_SPI 2 IRQ_TYPE_EDGE_RISING>, 175 + <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>, 176 + <GIC_SPI 4 IRQ_TYPE_EDGE_RISING>, 177 + <GIC_SPI 5 IRQ_TYPE_EDGE_RISING>, 178 + <GIC_SPI 6 IRQ_TYPE_EDGE_RISING>, 179 + <GIC_SPI 7 IRQ_TYPE_EDGE_RISING>, 180 + <GIC_SPI 8 IRQ_TYPE_EDGE_RISING>, 181 + <GIC_SPI 9 IRQ_TYPE_EDGE_RISING>, 182 + <GIC_SPI 10 IRQ_TYPE_EDGE_RISING>, 183 + <GIC_SPI 11 IRQ_TYPE_EDGE_RISING>, 184 + <GIC_SPI 12 IRQ_TYPE_EDGE_RISING>, 185 + <GIC_SPI 13 IRQ_TYPE_EDGE_RISING>, 186 + <GIC_SPI 14 IRQ_TYPE_EDGE_RISING>, 187 + <GIC_SPI 15 IRQ_TYPE_EDGE_RISING>, 188 + <GIC_SPI 16 IRQ_TYPE_EDGE_RISING>, 189 + <GIC_SPI 17 IRQ_TYPE_EDGE_RISING>, 190 + <GIC_SPI 18 IRQ_TYPE_EDGE_RISING>, 191 + <GIC_SPI 19 IRQ_TYPE_EDGE_RISING>, 192 + <GIC_SPI 20 IRQ_TYPE_EDGE_RISING>, 193 + <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>, 194 + <GIC_SPI 22 IRQ_TYPE_EDGE_RISING>, 195 + <GIC_SPI 23 IRQ_TYPE_EDGE_RISING>, 196 + <GIC_SPI 24 IRQ_TYPE_EDGE_RISING>, 197 + <GIC_SPI 25 IRQ_TYPE_EDGE_RISING>, 198 + <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>, 199 + <GIC_SPI 27 IRQ_TYPE_EDGE_RISING>, 200 + <GIC_SPI 28 IRQ_TYPE_EDGE_RISING>, 201 + <GIC_SPI 29 IRQ_TYPE_EDGE_RISING>, 202 + <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>, 203 + <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>, 204 + <GIC_SPI 406 IRQ_TYPE_EDGE_RISING>, 205 + <GIC_SPI 407 IRQ_TYPE_EDGE_RISING>, 206 + <GIC_SPI 408 IRQ_TYPE_EDGE_RISING>, 207 + <GIC_SPI 409 IRQ_TYPE_EDGE_RISING>, 208 + <GIC_SPI 410 IRQ_TYPE_EDGE_RISING>, 209 + <GIC_SPI 411 IRQ_TYPE_EDGE_RISING>, 210 + <GIC_SPI 412 IRQ_TYPE_EDGE_RISING>, 211 + <GIC_SPI 413 IRQ_TYPE_EDGE_RISING>, 212 + <GIC_SPI 414 IRQ_TYPE_EDGE_RISING>, 213 + <GIC_SPI 415 IRQ_TYPE_EDGE_RISING>, 214 + <GIC_SPI 416 IRQ_TYPE_EDGE_RISING>, 215 + <GIC_SPI 417 IRQ_TYPE_EDGE_RISING>, 216 + <GIC_SPI 418 IRQ_TYPE_EDGE_RISING>; 217 + interrupt-names = "intcpu0", "intcpu1", "intcpu2", 218 + "intcpu3", "intcpu4", "intcpu5", 219 + "intcpu6", "intcpu7", "intcpu8", 220 + "intcpu9", "intcpu10", "intcpu11", 221 + "intcpu12", "intcpu13", "intcpu14", 222 + "intcpu15", 223 + "irq0", "irq1", "irq2", "irq3", 224 + "irq4", "irq5", "irq6", "irq7", 225 + "irq8", "irq9", "irq10", "irq11", 226 + "irq12", "irq13", "irq14", "irq15", 227 + "sei", 228 + "ca55-err0", "ca55-err1", 229 + "cr520-err0", "cr520-err1", 230 + "cr521-err0", "cr521-err1", 231 + "peri-err0", "peri-err1", 232 + "dsmif-err0", "dsmif-err1", 233 + "encif-err0", "encif-err1"; 234 + clocks = <&cpg CPG_CORE R9A09G077_CLK_PCLKM>; 235 + power-domains = <&cpg>; 236 + };
+1
Documentation/devicetree/bindings/interrupt-controller/renesas,rzv2h-icu.yaml
··· 22 22 compatible: 23 23 enum: 24 24 - renesas,r9a09g047-icu # RZ/G3E 25 + - renesas,r9a09g056-icu # RZ/V2N 25 26 - renesas,r9a09g057-icu # RZ/V2H(P) 26 27 27 28 '#interrupt-cells':
+3 -1
Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml
··· 108 108 riscv,ndev: 109 109 $ref: /schemas/types.yaml#/definitions/uint32 110 110 description: 111 - Specifies how many external interrupts are supported by this controller. 111 + Specifies how many external (device) interrupts are supported by this 112 + controller. Note that source 0 is reserved in PLIC, so the valid 113 + interrupt sources are 1 to riscv,ndev inclusive. 112 114 113 115 clocks: true 114 116
+33 -5
Documentation/devicetree/bindings/interrupt-controller/ti,sci-intr.yaml
··· 15 15 description: | 16 16 The Interrupt Router (INTR) module provides a mechanism to mux M 17 17 interrupt inputs to N interrupt outputs, where all M inputs are selectable 18 - to be driven per N output. An Interrupt Router can either handle edge 19 - triggered or level triggered interrupts and that is fixed in hardware. 18 + to be driven per N output. 20 19 21 20 Interrupt Router 22 21 +----------------------+ ··· 63 64 interrupt-controller: true 64 65 65 66 '#interrupt-cells': 66 - const: 1 67 + enum: [1, 2] 67 68 description: | 68 - The 1st cell should contain interrupt router input hw number. 69 + Number of cells in interrupt specifier. Depends on ti,intr-trigger-type: 70 + - If ti,intr-trigger-type is present: must be 1 71 + The 1st cell should contain interrupt router input hw number. 72 + - If ti,intr-trigger-type is absent: must be 2 73 + The 1st cell should contain interrupt router input hw number. 74 + The 2nd cell should contain interrupt trigger type (preserved by router). 69 75 70 76 ti,interrupt-ranges: 71 77 $ref: /schemas/types.yaml#/definitions/uint32-matrix ··· 86 82 - description: | 87 83 "limit" specifies the limit for translation 88 84 85 + if: 86 + required: 87 + - ti,intr-trigger-type 88 + then: 89 + properties: 90 + '#interrupt-cells': 91 + const: 1 92 + description: Interrupt ID only. Interrupt type is specified globally 93 + else: 94 + properties: 95 + '#interrupt-cells': 96 + const: 2 97 + description: Interrupt ID and corresponding interrupt type 98 + 89 99 required: 90 100 - compatible 91 - - ti,intr-trigger-type 92 101 - interrupt-controller 93 102 - '#interrupt-cells' 94 103 - ti,sci ··· 118 101 interrupt-controller; 119 102 interrupt-parent = <&gic500>; 120 103 #interrupt-cells = <1>; 104 + ti,sci = <&dmsc>; 105 + ti,sci-dev-id = <131>; 106 + ti,interrupt-ranges = <0 360 32>; 107 + }; 108 + 109 + - | 110 + interrupt-controller { 111 + compatible = "ti,sci-intr"; 112 + interrupt-controller; 113 + interrupt-parent = <&gic500>; 114 + #interrupt-cells = <2>; 121 115 ti,sci = <&dmsc>; 122 116 ti,sci-dev-id = <131>; 123 117 ti,interrupt-ranges = <0 360 32>;
+73
arch/arm64/boot/dts/renesas/r9a09g077.dtsi
··· 756 756 #power-domain-cells = <0>; 757 757 }; 758 758 759 + icu: interrupt-controller@802a0000 { 760 + compatible = "renesas,r9a09g077-icu"; 761 + reg = <0 0x802a0000 0 0x10000>, 762 + <0 0x812a0000 0 0x50>; 763 + #interrupt-cells = <2>; 764 + #address-cells = <0>; 765 + interrupt-controller; 766 + interrupts = <GIC_SPI 0 IRQ_TYPE_EDGE_RISING>, 767 + <GIC_SPI 1 IRQ_TYPE_EDGE_RISING>, 768 + <GIC_SPI 2 IRQ_TYPE_EDGE_RISING>, 769 + <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>, 770 + <GIC_SPI 4 IRQ_TYPE_EDGE_RISING>, 771 + <GIC_SPI 5 IRQ_TYPE_EDGE_RISING>, 772 + <GIC_SPI 6 IRQ_TYPE_EDGE_RISING>, 773 + <GIC_SPI 7 IRQ_TYPE_EDGE_RISING>, 774 + <GIC_SPI 8 IRQ_TYPE_EDGE_RISING>, 775 + <GIC_SPI 9 IRQ_TYPE_EDGE_RISING>, 776 + <GIC_SPI 10 IRQ_TYPE_EDGE_RISING>, 777 + <GIC_SPI 11 IRQ_TYPE_EDGE_RISING>, 778 + <GIC_SPI 12 IRQ_TYPE_EDGE_RISING>, 779 + <GIC_SPI 13 IRQ_TYPE_EDGE_RISING>, 780 + <GIC_SPI 14 IRQ_TYPE_EDGE_RISING>, 781 + <GIC_SPI 15 IRQ_TYPE_EDGE_RISING>, 782 + <GIC_SPI 16 IRQ_TYPE_EDGE_RISING>, 783 + <GIC_SPI 17 IRQ_TYPE_EDGE_RISING>, 784 + <GIC_SPI 18 IRQ_TYPE_EDGE_RISING>, 785 + <GIC_SPI 19 IRQ_TYPE_EDGE_RISING>, 786 + <GIC_SPI 20 IRQ_TYPE_EDGE_RISING>, 787 + <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>, 788 + <GIC_SPI 22 IRQ_TYPE_EDGE_RISING>, 789 + <GIC_SPI 23 IRQ_TYPE_EDGE_RISING>, 790 + <GIC_SPI 24 IRQ_TYPE_EDGE_RISING>, 791 + <GIC_SPI 25 IRQ_TYPE_EDGE_RISING>, 792 + <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>, 793 + <GIC_SPI 27 IRQ_TYPE_EDGE_RISING>, 794 + <GIC_SPI 28 IRQ_TYPE_EDGE_RISING>, 795 + <GIC_SPI 29 IRQ_TYPE_EDGE_RISING>, 796 + <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>, 797 + <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>, 798 + <GIC_SPI 406 IRQ_TYPE_EDGE_RISING>, 799 + <GIC_SPI 407 IRQ_TYPE_EDGE_RISING>, 800 + <GIC_SPI 408 IRQ_TYPE_EDGE_RISING>, 801 + <GIC_SPI 409 IRQ_TYPE_EDGE_RISING>, 802 + <GIC_SPI 410 IRQ_TYPE_EDGE_RISING>, 803 + <GIC_SPI 411 IRQ_TYPE_EDGE_RISING>, 804 + <GIC_SPI 412 IRQ_TYPE_EDGE_RISING>, 805 + <GIC_SPI 413 IRQ_TYPE_EDGE_RISING>, 806 + <GIC_SPI 414 IRQ_TYPE_EDGE_RISING>, 807 + <GIC_SPI 415 IRQ_TYPE_EDGE_RISING>, 808 + <GIC_SPI 416 IRQ_TYPE_EDGE_RISING>, 809 + <GIC_SPI 417 IRQ_TYPE_EDGE_RISING>, 810 + <GIC_SPI 418 IRQ_TYPE_EDGE_RISING>; 811 + interrupt-names = "intcpu0", "intcpu1", "intcpu2", 812 + "intcpu3", "intcpu4", "intcpu5", 813 + "intcpu6", "intcpu7", "intcpu8", 814 + "intcpu9", "intcpu10", "intcpu11", 815 + "intcpu12", "intcpu13", "intcpu14", 816 + "intcpu15", 817 + "irq0", "irq1", "irq2", "irq3", 818 + "irq4", "irq5", "irq6", "irq7", 819 + "irq8", "irq9", "irq10", "irq11", 820 + "irq12", "irq13", "irq14", "irq15", 821 + "sei", 822 + "ca55-err0", "ca55-err1", 823 + "cr520-err0", "cr520-err1", 824 + "cr521-err0", "cr521-err1", 825 + "peri-err0", "peri-err1", 826 + "dsmif-err0", "dsmif-err1", 827 + "encif-err0", "encif-err1"; 828 + clocks = <&cpg CPG_CORE R9A09G077_CLK_PCLKM>; 829 + power-domains = <&cpg>; 830 + }; 831 + 759 832 pinctrl: pinctrl@802c0000 { 760 833 compatible = "renesas,r9a09g077-pinctrl"; 761 834 reg = <0 0x802c0000 0 0x10000>,
+73
arch/arm64/boot/dts/renesas/r9a09g087.dtsi
··· 759 759 #power-domain-cells = <0>; 760 760 }; 761 761 762 + icu: interrupt-controller@802a0000 { 763 + compatible = "renesas,r9a09g087-icu", "renesas,r9a09g077-icu"; 764 + reg = <0 0x802a0000 0 0x10000>, 765 + <0 0x812a0000 0 0x50>; 766 + #interrupt-cells = <2>; 767 + #address-cells = <0>; 768 + interrupt-controller; 769 + interrupts = <GIC_SPI 0 IRQ_TYPE_EDGE_RISING>, 770 + <GIC_SPI 1 IRQ_TYPE_EDGE_RISING>, 771 + <GIC_SPI 2 IRQ_TYPE_EDGE_RISING>, 772 + <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>, 773 + <GIC_SPI 4 IRQ_TYPE_EDGE_RISING>, 774 + <GIC_SPI 5 IRQ_TYPE_EDGE_RISING>, 775 + <GIC_SPI 6 IRQ_TYPE_EDGE_RISING>, 776 + <GIC_SPI 7 IRQ_TYPE_EDGE_RISING>, 777 + <GIC_SPI 8 IRQ_TYPE_EDGE_RISING>, 778 + <GIC_SPI 9 IRQ_TYPE_EDGE_RISING>, 779 + <GIC_SPI 10 IRQ_TYPE_EDGE_RISING>, 780 + <GIC_SPI 11 IRQ_TYPE_EDGE_RISING>, 781 + <GIC_SPI 12 IRQ_TYPE_EDGE_RISING>, 782 + <GIC_SPI 13 IRQ_TYPE_EDGE_RISING>, 783 + <GIC_SPI 14 IRQ_TYPE_EDGE_RISING>, 784 + <GIC_SPI 15 IRQ_TYPE_EDGE_RISING>, 785 + <GIC_SPI 16 IRQ_TYPE_EDGE_RISING>, 786 + <GIC_SPI 17 IRQ_TYPE_EDGE_RISING>, 787 + <GIC_SPI 18 IRQ_TYPE_EDGE_RISING>, 788 + <GIC_SPI 19 IRQ_TYPE_EDGE_RISING>, 789 + <GIC_SPI 20 IRQ_TYPE_EDGE_RISING>, 790 + <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>, 791 + <GIC_SPI 22 IRQ_TYPE_EDGE_RISING>, 792 + <GIC_SPI 23 IRQ_TYPE_EDGE_RISING>, 793 + <GIC_SPI 24 IRQ_TYPE_EDGE_RISING>, 794 + <GIC_SPI 25 IRQ_TYPE_EDGE_RISING>, 795 + <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>, 796 + <GIC_SPI 27 IRQ_TYPE_EDGE_RISING>, 797 + <GIC_SPI 28 IRQ_TYPE_EDGE_RISING>, 798 + <GIC_SPI 29 IRQ_TYPE_EDGE_RISING>, 799 + <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>, 800 + <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>, 801 + <GIC_SPI 406 IRQ_TYPE_EDGE_RISING>, 802 + <GIC_SPI 407 IRQ_TYPE_EDGE_RISING>, 803 + <GIC_SPI 408 IRQ_TYPE_EDGE_RISING>, 804 + <GIC_SPI 409 IRQ_TYPE_EDGE_RISING>, 805 + <GIC_SPI 410 IRQ_TYPE_EDGE_RISING>, 806 + <GIC_SPI 411 IRQ_TYPE_EDGE_RISING>, 807 + <GIC_SPI 412 IRQ_TYPE_EDGE_RISING>, 808 + <GIC_SPI 413 IRQ_TYPE_EDGE_RISING>, 809 + <GIC_SPI 414 IRQ_TYPE_EDGE_RISING>, 810 + <GIC_SPI 415 IRQ_TYPE_EDGE_RISING>, 811 + <GIC_SPI 416 IRQ_TYPE_EDGE_RISING>, 812 + <GIC_SPI 417 IRQ_TYPE_EDGE_RISING>, 813 + <GIC_SPI 418 IRQ_TYPE_EDGE_RISING>; 814 + interrupt-names = "intcpu0", "intcpu1", "intcpu2", 815 + "intcpu3", "intcpu4", "intcpu5", 816 + "intcpu6", "intcpu7", "intcpu8", 817 + "intcpu9", "intcpu10", "intcpu11", 818 + "intcpu12", "intcpu13", "intcpu14", 819 + "intcpu15", 820 + "irq0", "irq1", "irq2", "irq3", 821 + "irq4", "irq5", "irq6", "irq7", 822 + "irq8", "irq9", "irq10", "irq11", 823 + "irq12", "irq13", "irq14", "irq15", 824 + "sei", 825 + "ca55-err0", "ca55-err1", 826 + "cr520-err0", "cr520-err1", 827 + "cr521-err0", "cr521-err1", 828 + "peri-err0", "peri-err1", 829 + "dsmif-err0", "dsmif-err1", 830 + "encif-err0", "encif-err1"; 831 + clocks = <&cpg CPG_CORE R9A09G087_CLK_PCLKM>; 832 + power-domains = <&cpg>; 833 + }; 834 + 762 835 pinctrl: pinctrl@802c0000 { 763 836 compatible = "renesas,r9a09g087-pinctrl"; 764 837 reg = <0 0x802c0000 0 0x10000>,
+13 -6
drivers/irqchip/Kconfig
··· 297 297 Enable support for the Renesas RZ/G2L (and alike SoC) Interrupt Controller 298 298 for external devices. 299 299 300 + config RENESAS_RZT2H_ICU 301 + bool "Renesas RZ/{T2H,N2H} ICU support" if COMPILE_TEST 302 + select GENERIC_IRQ_CHIP 303 + select IRQ_DOMAIN_HIERARCHY 304 + help 305 + Enable support for the Renesas RZ/{T2H,N2H} Interrupt Controller 306 + (ICU). 307 + 300 308 config RENESAS_RZV2H_ICU 301 309 bool "Renesas RZ/V2H(P) ICU support" if COMPILE_TEST 302 310 select GENERIC_IRQ_CHIP ··· 706 698 707 699 config LOONGSON_LIOINTC 708 700 bool "Loongson Local I/O Interrupt Controller" 709 - depends on MACH_LOONGSON64 701 + depends on MACH_LOONGSON64 || LOONGARCH 710 702 default y 711 703 select IRQ_DOMAIN 712 704 select GENERIC_IRQ_CHIP ··· 716 708 config LOONGSON_EIOINTC 717 709 bool "Loongson Extend I/O Interrupt Controller" 718 710 depends on LOONGARCH 719 - depends on MACH_LOONGSON64 720 711 default MACH_LOONGSON64 721 712 select IRQ_DOMAIN_HIERARCHY 722 713 select GENERIC_IRQ_CHIP ··· 733 726 734 727 config LOONGSON_HTVEC 735 728 bool "Loongson HyperTransport Interrupt Vector Controller" 736 - depends on MACH_LOONGSON64 729 + depends on MACH_LOONGSON64 || LOONGARCH 737 730 default MACH_LOONGSON64 738 731 select IRQ_DOMAIN_HIERARCHY 739 732 help ··· 741 734 742 735 config LOONGSON_PCH_PIC 743 736 bool "Loongson PCH PIC Controller" 744 - depends on MACH_LOONGSON64 737 + depends on MACH_LOONGSON64 || LOONGARCH 745 738 default MACH_LOONGSON64 746 739 select IRQ_DOMAIN_HIERARCHY 747 740 select IRQ_FASTEOI_HIERARCHY_HANDLERS ··· 750 743 751 744 config LOONGSON_PCH_MSI 752 745 bool "Loongson PCH MSI Controller" 753 - depends on MACH_LOONGSON64 746 + depends on MACH_LOONGSON64 || LOONGARCH 754 747 depends on PCI 755 748 default MACH_LOONGSON64 756 749 select IRQ_DOMAIN_HIERARCHY ··· 762 755 config LOONGSON_PCH_LPC 763 756 bool "Loongson PCH LPC Controller" 764 757 depends on LOONGARCH 765 - depends on MACH_LOONGSON64 758 + depends on MACH_LOONGSON64 || LOONGARCH 766 759 default MACH_LOONGSON64 767 760 select IRQ_DOMAIN_HIERARCHY 768 761 help
+1
drivers/irqchip/Makefile
··· 54 54 obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o 55 55 obj-$(CONFIG_RENESAS_RZA1_IRQC) += irq-renesas-rza1.o 56 56 obj-$(CONFIG_RENESAS_RZG2L_IRQC) += irq-renesas-rzg2l.o 57 + obj-$(CONFIG_RENESAS_RZT2H_ICU) += irq-renesas-rzt2h.o 57 58 obj-$(CONFIG_RENESAS_RZV2H_ICU) += irq-renesas-rzv2h.o 58 59 obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o 59 60 obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o
+5 -3
drivers/irqchip/irq-aclint-sswi.c
··· 109 109 if (!is_of_node(fwnode)) 110 110 return -EINVAL; 111 111 112 - reg = of_iomap(to_of_node(fwnode), 0); 113 - if (!reg) 114 - return -ENOMEM; 112 + reg = of_io_request_and_map(to_of_node(fwnode), 0, NULL); 113 + if (IS_ERR(reg)) { 114 + pr_err("%pfwP: Failed to map MMIO region\n", fwnode); 115 + return PTR_ERR(reg); 116 + } 115 117 116 118 /* Parse SSWI setting */ 117 119 rc = aclint_sswi_parse_irq(fwnode, reg);
+1 -2
drivers/irqchip/irq-aspeed-scu-ic.c
··· 104 104 struct aspeed_scu_ic *scu_ic = irq_desc_get_handler_data(desc); 105 105 struct irq_chip *chip = irq_desc_get_chip(desc); 106 106 unsigned long bit, enabled, max, status; 107 - unsigned int sts, mask; 107 + unsigned int sts; 108 108 109 109 chained_irq_enter(chip, desc); 110 110 111 - mask = scu_ic->irq_enable; 112 111 sts = readl(scu_ic->base + scu_ic->isr); 113 112 enabled = sts & scu_ic->irq_enable; 114 113 sts = readl(scu_ic->base + scu_ic->isr);
+1 -1
drivers/irqchip/irq-gic-v5-its.c
··· 902 902 event_id_base = info->hwirq; 903 903 904 904 if (event_id_base >= its_dev->num_events) { 905 - pr_err("EventID ouside of ITT range; cannot allocate an ITT entry!\n"); 905 + pr_err("EventID outside of ITT range; cannot allocate an ITT entry!\n"); 906 906 907 907 return -EINVAL; 908 908 }
+8 -6
drivers/irqchip/irq-loongarch-avec.c
··· 58 58 59 59 static inline void avecintc_enable(void) 60 60 { 61 + #ifdef CONFIG_MACH_LOONGSON64 61 62 u64 value; 62 63 63 64 value = iocsr_read64(LOONGARCH_IOCSR_MISC_FUNC); 64 65 value |= IOCSR_MISC_FUNC_AVEC_EN; 65 66 iocsr_write64(value, LOONGARCH_IOCSR_MISC_FUNC); 67 + #endif 66 68 } 67 69 68 70 static inline void avecintc_ack_irq(struct irq_data *d) ··· 169 167 struct pending_list *plist = this_cpu_ptr(&pending_list); 170 168 struct avecintc_data *adata, *tdata; 171 169 int cpu, vector, bias; 172 - uint64_t isr; 170 + unsigned long isr; 173 171 174 172 guard(raw_spinlock)(&loongarch_avec.lock); 175 173 ··· 179 177 bias = vector / VECTORS_PER_REG; 180 178 switch (bias) { 181 179 case 0: 182 - isr = csr_read64(LOONGARCH_CSR_ISR0); 180 + isr = csr_read(LOONGARCH_CSR_ISR0); 183 181 break; 184 182 case 1: 185 - isr = csr_read64(LOONGARCH_CSR_ISR1); 183 + isr = csr_read(LOONGARCH_CSR_ISR1); 186 184 break; 187 185 case 2: 188 - isr = csr_read64(LOONGARCH_CSR_ISR2); 186 + isr = csr_read(LOONGARCH_CSR_ISR2); 189 187 break; 190 188 case 3: 191 - isr = csr_read64(LOONGARCH_CSR_ISR3); 189 + isr = csr_read(LOONGARCH_CSR_ISR3); 192 190 break; 193 191 } 194 192 ··· 236 234 chained_irq_enter(chip, desc); 237 235 238 236 while (true) { 239 - unsigned long vector = csr_read64(LOONGARCH_CSR_IRR); 237 + unsigned long vector = csr_read(LOONGARCH_CSR_IRR); 240 238 if (vector & IRR_INVALID_MASK) 241 239 break; 242 240
+30 -6
drivers/irqchip/irq-loongson-eiointc.c
··· 37 37 #define EXTIOI_ENABLE_INT_ENCODE BIT(2) 38 38 #define EXTIOI_ENABLE_CPU_ENCODE BIT(3) 39 39 40 - #define VEC_REG_COUNT 4 41 - #define VEC_COUNT_PER_REG 64 42 - #define VEC_COUNT (VEC_REG_COUNT * VEC_COUNT_PER_REG) 40 + #define VEC_COUNT 256 41 + #define VEC_COUNT_PER_REG BITS_PER_LONG 42 + #define VEC_REG_COUNT (VEC_COUNT / BITS_PER_LONG) 43 43 #define VEC_REG_IDX(irq_id) ((irq_id) / VEC_COUNT_PER_REG) 44 44 #define VEC_REG_BIT(irq_id) ((irq_id) % VEC_COUNT_PER_REG) 45 45 #define EIOINTC_ALL_ENABLE 0xffffffff ··· 85 85 86 86 static void eiointc_enable(void) 87 87 { 88 + #ifdef CONFIG_MACH_LOONGSON64 88 89 uint64_t misc; 89 90 90 91 misc = iocsr_read64(LOONGARCH_IOCSR_MISC_FUNC); 91 92 misc |= IOCSR_MISC_FUNC_EXT_IOI_EN; 92 93 iocsr_write64(misc, LOONGARCH_IOCSR_MISC_FUNC); 94 + #endif 93 95 } 94 96 95 97 static int cpu_to_eio_node(int cpu) ··· 283 281 return 0; 284 282 } 285 283 284 + #if VEC_COUNT_PER_REG == 32 285 + static inline unsigned long read_isr(int i) 286 + { 287 + return iocsr_read32(EIOINTC_REG_ISR + (i << 2)); 288 + } 289 + 290 + static inline void write_isr(int i, unsigned long val) 291 + { 292 + iocsr_write32(val, EIOINTC_REG_ISR + (i << 2)); 293 + } 294 + #else 295 + static inline unsigned long read_isr(int i) 296 + { 297 + return iocsr_read64(EIOINTC_REG_ISR + (i << 3)); 298 + } 299 + 300 + static inline void write_isr(int i, unsigned long val) 301 + { 302 + iocsr_write64(val, EIOINTC_REG_ISR + (i << 3)); 303 + } 304 + #endif 305 + 286 306 static void eiointc_irq_dispatch(struct irq_desc *desc) 287 307 { 288 308 struct eiointc_ip_route *info = irq_desc_get_handler_data(desc); 289 309 struct irq_chip *chip = irq_desc_get_chip(desc); 310 + unsigned long pending; 290 311 bool handled = false; 291 - u64 pending; 292 312 int i; 293 313 294 314 chained_irq_enter(chip, desc); ··· 323 299 * read ISR for these 64 interrupt vectors rather than all vectors 324 300 */ 325 301 for (i = info->start; i < info->end; i++) { 326 - pending = iocsr_read64(EIOINTC_REG_ISR + (i << 3)); 302 + pending = read_isr(i); 327 303 328 304 /* Skip handling if pending bitmap is zero */ 329 305 if (!pending) 330 306 continue; 331 307 332 308 /* Clear the IRQs */ 333 - iocsr_write64(pending, EIOINTC_REG_ISR + (i << 3)); 309 + write_isr(i, pending); 334 310 while (pending) { 335 311 int bit = __ffs(pending); 336 312 int irq = bit + VEC_COUNT_PER_REG * i;
+6 -8
drivers/irqchip/irq-loongson-htvec.c
··· 295 295 return 0; 296 296 } 297 297 298 - int __init htvec_acpi_init(struct irq_domain *parent, 299 - struct acpi_madt_ht_pic *acpi_htvec) 298 + int __init htvec_acpi_init(struct irq_domain *parent, struct acpi_madt_ht_pic *acpi_htvec) 300 299 { 301 - int i, ret; 302 - int num_parents, parent_irq[8]; 300 + int i, ret, num_parents, parent_irq[8]; 303 301 struct fwnode_handle *domain_handle; 302 + phys_addr_t addr; 304 303 305 304 if (!acpi_htvec) 306 305 return -EINVAL; 307 306 308 307 num_parents = HTVEC_MAX_PARENT_IRQ; 308 + addr = (phys_addr_t)acpi_htvec->address; 309 309 310 - domain_handle = irq_domain_alloc_fwnode(&acpi_htvec->address); 310 + domain_handle = irq_domain_alloc_fwnode(&addr); 311 311 if (!domain_handle) { 312 312 pr_err("Unable to allocate domain handle\n"); 313 313 return -ENOMEM; ··· 317 317 for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++) 318 318 parent_irq[i] = irq_create_mapping(parent, acpi_htvec->cascade[i]); 319 319 320 - ret = htvec_init(acpi_htvec->address, acpi_htvec->size, 321 - num_parents, parent_irq, domain_handle); 322 - 320 + ret = htvec_init(addr, acpi_htvec->size, num_parents, parent_irq, domain_handle); 323 321 if (ret == 0) 324 322 ret = acpi_cascade_irqdomain_init(); 325 323 else
+4 -4
drivers/irqchip/irq-loongson-liointc.c
··· 394 394 395 395 int __init liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic *acpi_liointc) 396 396 { 397 - int ret; 397 + phys_addr_t addr = (phys_addr_t)acpi_liointc->address; 398 398 struct fwnode_handle *domain_handle; 399 + int ret; 399 400 400 401 parent_int_map[0] = acpi_liointc->cascade_map[0]; 401 402 parent_int_map[1] = acpi_liointc->cascade_map[1]; ··· 404 403 parent_irq[0] = irq_create_mapping(parent, acpi_liointc->cascade[0]); 405 404 parent_irq[1] = irq_create_mapping(parent, acpi_liointc->cascade[1]); 406 405 407 - domain_handle = irq_domain_alloc_fwnode(&acpi_liointc->address); 406 + domain_handle = irq_domain_alloc_fwnode(&addr); 408 407 if (!domain_handle) { 409 408 pr_err("Unable to allocate domain handle\n"); 410 409 return -ENOMEM; 411 410 } 412 411 413 - ret = liointc_init(acpi_liointc->address, acpi_liointc->size, 414 - 1, domain_handle, NULL); 412 + ret = liointc_init(addr, acpi_liointc->size, 1, domain_handle, NULL); 415 413 if (ret == 0) 416 414 ret = acpi_cascade_irqdomain_init(); 417 415 else
+5 -4
drivers/irqchip/irq-loongson-pch-msi.c
··· 263 263 264 264 int __init pch_msi_acpi_init(struct irq_domain *parent, struct acpi_madt_msi_pic *acpi_pchmsi) 265 265 { 266 - int ret; 266 + phys_addr_t msg_address = (phys_addr_t)acpi_pchmsi->msg_address; 267 267 struct fwnode_handle *domain_handle; 268 + int ret; 268 269 269 - domain_handle = irq_domain_alloc_fwnode(&acpi_pchmsi->msg_address); 270 - ret = pch_msi_init(acpi_pchmsi->msg_address, acpi_pchmsi->start, 271 - acpi_pchmsi->count, parent, domain_handle); 270 + domain_handle = irq_domain_alloc_fwnode(&msg_address); 271 + ret = pch_msi_init(msg_address, acpi_pchmsi->start, acpi_pchmsi->count, 272 + parent, domain_handle); 272 273 if (ret < 0) 273 274 irq_domain_free_fwnode(domain_handle); 274 275
+7 -7
drivers/irqchip/irq-loongson-pch-pic.c
··· 343 343 priv->table[i] = PIC_UNDEF_VECTOR; 344 344 345 345 priv->ht_vec_base = vec_base; 346 - priv->vec_count = ((readq(priv->base) >> 48) & 0xff) + 1; 346 + priv->vec_count = ((readl(priv->base + 4) >> 16) & 0xff) + 1; 347 347 priv->gsi_base = gsi_base; 348 348 349 349 priv->pic_domain = irq_domain_create_hierarchy(parent_domain, 0, ··· 446 446 return 0; 447 447 } 448 448 449 - int __init pch_pic_acpi_init(struct irq_domain *parent, 450 - struct acpi_madt_bio_pic *acpi_pchpic) 449 + int __init pch_pic_acpi_init(struct irq_domain *parent, struct acpi_madt_bio_pic *acpi_pchpic) 451 450 { 452 - int ret; 451 + phys_addr_t addr = (phys_addr_t)acpi_pchpic->address; 453 452 struct fwnode_handle *domain_handle; 453 + int ret; 454 454 455 455 if (find_pch_pic(acpi_pchpic->gsi_base) >= 0) 456 456 return 0; 457 457 458 - domain_handle = irq_domain_alloc_fwnode(&acpi_pchpic->address); 458 + domain_handle = irq_domain_alloc_fwnode(&addr); 459 459 if (!domain_handle) { 460 460 pr_err("Unable to allocate domain handle\n"); 461 461 return -ENOMEM; 462 462 } 463 463 464 - ret = pch_pic_init(acpi_pchpic->address, acpi_pchpic->size, 465 - 0, parent, domain_handle, acpi_pchpic->gsi_base); 464 + ret = pch_pic_init(addr, acpi_pchpic->size, 0, parent, 465 + domain_handle, acpi_pchpic->gsi_base); 466 466 467 467 if (ret < 0) { 468 468 irq_domain_free_fwnode(domain_handle);
+280
drivers/irqchip/irq-renesas-rzt2h.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/bitfield.h> 4 + #include <linux/err.h> 5 + #include <linux/io.h> 6 + #include <linux/irqchip.h> 7 + #include <linux/irqchip/irq-renesas-rzt2h.h> 8 + #include <linux/irqdomain.h> 9 + #include <linux/of_platform.h> 10 + #include <linux/pm_runtime.h> 11 + #include <linux/reset.h> 12 + #include <linux/spinlock.h> 13 + 14 + #define RZT2H_ICU_INTCPU_NS_START 0 15 + #define RZT2H_ICU_INTCPU_NS_COUNT 14 16 + 17 + #define RZT2H_ICU_INTCPU_S_START (RZT2H_ICU_INTCPU_NS_START + \ 18 + RZT2H_ICU_INTCPU_NS_COUNT) 19 + #define RZT2H_ICU_INTCPU_S_COUNT 2 20 + 21 + #define RZT2H_ICU_IRQ_NS_START (RZT2H_ICU_INTCPU_S_START + \ 22 + RZT2H_ICU_INTCPU_S_COUNT) 23 + #define RZT2H_ICU_IRQ_NS_COUNT 14 24 + 25 + #define RZT2H_ICU_IRQ_S_START (RZT2H_ICU_IRQ_NS_START + \ 26 + RZT2H_ICU_IRQ_NS_COUNT) 27 + #define RZT2H_ICU_IRQ_S_COUNT 2 28 + 29 + #define RZT2H_ICU_SEI_START (RZT2H_ICU_IRQ_S_START + \ 30 + RZT2H_ICU_IRQ_S_COUNT) 31 + #define RZT2H_ICU_SEI_COUNT 1 32 + 33 + #define RZT2H_ICU_NUM_IRQ (RZT2H_ICU_INTCPU_NS_COUNT + \ 34 + RZT2H_ICU_INTCPU_S_COUNT + \ 35 + RZT2H_ICU_IRQ_NS_COUNT + \ 36 + RZT2H_ICU_IRQ_S_COUNT + \ 37 + RZT2H_ICU_SEI_COUNT) 38 + 39 + #define RZT2H_ICU_IRQ_IN_RANGE(n, type) \ 40 + ((n) >= RZT2H_ICU_##type##_START && \ 41 + (n) < RZT2H_ICU_##type##_START + RZT2H_ICU_##type##_COUNT) 42 + 43 + #define RZT2H_ICU_PORTNF_MD 0xc 44 + #define RZT2H_ICU_PORTNF_MDi_MASK(i) (GENMASK(1, 0) << ((i) * 2)) 45 + #define RZT2H_ICU_PORTNF_MDi_PREP(i, val) (FIELD_PREP(GENMASK(1, 0), val) << ((i) * 2)) 46 + 47 + #define RZT2H_ICU_MD_LOW_LEVEL 0b00 48 + #define RZT2H_ICU_MD_FALLING_EDGE 0b01 49 + #define RZT2H_ICU_MD_RISING_EDGE 0b10 50 + #define RZT2H_ICU_MD_BOTH_EDGES 0b11 51 + 52 + #define RZT2H_ICU_DMACn_RSSELi(n, i) (0x7d0 + 0x18 * (n) + 0x4 * (i)) 53 + #define RZT2H_ICU_DMAC_REQ_SELx_MASK(x) (GENMASK(9, 0) << ((x) * 10)) 54 + #define RZT2H_ICU_DMAC_REQ_SELx_PREP(x, val) (FIELD_PREP(GENMASK(9, 0), val) << ((x) * 10)) 55 + 56 + struct rzt2h_icu_priv { 57 + void __iomem *base_ns; 58 + void __iomem *base_s; 59 + struct irq_fwspec fwspec[RZT2H_ICU_NUM_IRQ]; 60 + raw_spinlock_t lock; 61 + }; 62 + 63 + void rzt2h_icu_register_dma_req(struct platform_device *icu_dev, u8 dmac_index, u8 dmac_channel, 64 + u16 req_no) 65 + { 66 + struct rzt2h_icu_priv *priv = platform_get_drvdata(icu_dev); 67 + u8 y, upper; 68 + u32 val; 69 + 70 + y = dmac_channel / 3; 71 + upper = dmac_channel % 3; 72 + 73 + guard(raw_spinlock_irqsave)(&priv->lock); 74 + val = readl(priv->base_ns + RZT2H_ICU_DMACn_RSSELi(dmac_index, y)); 75 + val &= ~RZT2H_ICU_DMAC_REQ_SELx_MASK(upper); 76 + val |= RZT2H_ICU_DMAC_REQ_SELx_PREP(upper, req_no); 77 + writel(val, priv->base_ns + RZT2H_ICU_DMACn_RSSELi(dmac_index, y)); 78 + } 79 + EXPORT_SYMBOL_GPL(rzt2h_icu_register_dma_req); 80 + 81 + static inline struct rzt2h_icu_priv *irq_data_to_priv(struct irq_data *data) 82 + { 83 + return data->domain->host_data; 84 + } 85 + 86 + static inline int rzt2h_icu_irq_to_offset(struct irq_data *d, void __iomem **base, 87 + unsigned int *offset) 88 + { 89 + struct rzt2h_icu_priv *priv = irq_data_to_priv(d); 90 + unsigned int hwirq = irqd_to_hwirq(d); 91 + 92 + /* 93 + * Safety IRQs and SEI use a separate register space from the non-safety IRQs. 94 + * SEI interrupt number follows immediately after the safety IRQs. 95 + */ 96 + if (RZT2H_ICU_IRQ_IN_RANGE(hwirq, IRQ_NS)) { 97 + *offset = hwirq - RZT2H_ICU_IRQ_NS_START; 98 + *base = priv->base_ns; 99 + } else if (RZT2H_ICU_IRQ_IN_RANGE(hwirq, IRQ_S) || RZT2H_ICU_IRQ_IN_RANGE(hwirq, SEI)) { 100 + *offset = hwirq - RZT2H_ICU_IRQ_S_START; 101 + *base = priv->base_s; 102 + } else { 103 + return -EINVAL; 104 + } 105 + return 0; 106 + } 107 + 108 + static int rzt2h_icu_irq_set_type(struct irq_data *d, unsigned int type) 109 + { 110 + struct rzt2h_icu_priv *priv = irq_data_to_priv(d); 111 + unsigned int offset, parent_type; 112 + void __iomem *base; 113 + u32 val, md; 114 + int ret; 115 + 116 + ret = rzt2h_icu_irq_to_offset(d, &base, &offset); 117 + if (ret) 118 + return ret; 119 + 120 + switch (type & IRQ_TYPE_SENSE_MASK) { 121 + case IRQ_TYPE_LEVEL_LOW: 122 + md = RZT2H_ICU_MD_LOW_LEVEL; 123 + parent_type = IRQ_TYPE_LEVEL_HIGH; 124 + break; 125 + case IRQ_TYPE_EDGE_FALLING: 126 + md = RZT2H_ICU_MD_FALLING_EDGE; 127 + parent_type = IRQ_TYPE_EDGE_RISING; 128 + break; 129 + case IRQ_TYPE_EDGE_RISING: 130 + md = RZT2H_ICU_MD_RISING_EDGE; 131 + parent_type = IRQ_TYPE_EDGE_RISING; 132 + break; 133 + case IRQ_TYPE_EDGE_BOTH: 134 + md = RZT2H_ICU_MD_BOTH_EDGES; 135 + parent_type = IRQ_TYPE_EDGE_RISING; 136 + break; 137 + default: 138 + return -EINVAL; 139 + } 140 + 141 + scoped_guard(raw_spinlock, &priv->lock) { 142 + val = readl_relaxed(base + RZT2H_ICU_PORTNF_MD); 143 + val &= ~RZT2H_ICU_PORTNF_MDi_MASK(offset); 144 + val |= RZT2H_ICU_PORTNF_MDi_PREP(offset, md); 145 + writel_relaxed(val, base + RZT2H_ICU_PORTNF_MD); 146 + } 147 + 148 + return irq_chip_set_type_parent(d, parent_type); 149 + } 150 + 151 + static int rzt2h_icu_set_type(struct irq_data *d, unsigned int type) 152 + { 153 + unsigned int hw_irq = irqd_to_hwirq(d); 154 + 155 + /* IRQn and SEI are selectable, others are edge-only. */ 156 + if (RZT2H_ICU_IRQ_IN_RANGE(hw_irq, IRQ_NS) || 157 + RZT2H_ICU_IRQ_IN_RANGE(hw_irq, IRQ_S) || 158 + RZT2H_ICU_IRQ_IN_RANGE(hw_irq, SEI)) 159 + return rzt2h_icu_irq_set_type(d, type); 160 + 161 + if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_EDGE_RISING) 162 + return -EINVAL; 163 + 164 + return irq_chip_set_type_parent(d, IRQ_TYPE_EDGE_RISING); 165 + } 166 + 167 + static const struct irq_chip rzt2h_icu_chip = { 168 + .name = "rzt2h-icu", 169 + .irq_mask = irq_chip_mask_parent, 170 + .irq_unmask = irq_chip_unmask_parent, 171 + .irq_eoi = irq_chip_eoi_parent, 172 + .irq_set_type = rzt2h_icu_set_type, 173 + .irq_set_wake = irq_chip_set_wake_parent, 174 + .irq_set_affinity = irq_chip_set_affinity_parent, 175 + .irq_retrigger = irq_chip_retrigger_hierarchy, 176 + .irq_get_irqchip_state = irq_chip_get_parent_state, 177 + .irq_set_irqchip_state = irq_chip_set_parent_state, 178 + .flags = IRQCHIP_MASK_ON_SUSPEND | 179 + IRQCHIP_SET_TYPE_MASKED | 180 + IRQCHIP_SKIP_SET_WAKE, 181 + }; 182 + 183 + static int rzt2h_icu_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, 184 + void *arg) 185 + { 186 + struct rzt2h_icu_priv *priv = domain->host_data; 187 + irq_hw_number_t hwirq; 188 + unsigned int type; 189 + int ret; 190 + 191 + ret = irq_domain_translate_twocell(domain, arg, &hwirq, &type); 192 + if (ret) 193 + return ret; 194 + 195 + ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &rzt2h_icu_chip, NULL); 196 + if (ret) 197 + return ret; 198 + 199 + return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &priv->fwspec[hwirq]); 200 + } 201 + 202 + static const struct irq_domain_ops rzt2h_icu_domain_ops = { 203 + .alloc = rzt2h_icu_alloc, 204 + .free = irq_domain_free_irqs_common, 205 + .translate = irq_domain_translate_twocell, 206 + }; 207 + 208 + static int rzt2h_icu_parse_interrupts(struct rzt2h_icu_priv *priv, struct device_node *np) 209 + { 210 + struct of_phandle_args map; 211 + unsigned int i; 212 + int ret; 213 + 214 + for (i = 0; i < RZT2H_ICU_NUM_IRQ; i++) { 215 + ret = of_irq_parse_one(np, i, &map); 216 + if (ret) 217 + return ret; 218 + 219 + of_phandle_args_to_fwspec(np, map.args, map.args_count, &priv->fwspec[i]); 220 + } 221 + 222 + return 0; 223 + } 224 + 225 + static int rzt2h_icu_init(struct platform_device *pdev, struct device_node *parent) 226 + { 227 + struct irq_domain *irq_domain, *parent_domain; 228 + struct device_node *node = pdev->dev.of_node; 229 + struct device *dev = &pdev->dev; 230 + struct rzt2h_icu_priv *priv; 231 + int ret; 232 + 233 + parent_domain = irq_find_host(parent); 234 + if (!parent_domain) 235 + return dev_err_probe(dev, -ENODEV, "cannot find parent domain\n"); 236 + 237 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 238 + if (!priv) 239 + return -ENOMEM; 240 + 241 + raw_spin_lock_init(&priv->lock); 242 + 243 + platform_set_drvdata(pdev, priv); 244 + 245 + priv->base_ns = devm_of_iomap(dev, dev->of_node, 0, NULL); 246 + if (IS_ERR(priv->base_ns)) 247 + return PTR_ERR(priv->base_ns); 248 + 249 + priv->base_s = devm_of_iomap(dev, dev->of_node, 1, NULL); 250 + if (IS_ERR(priv->base_s)) 251 + return PTR_ERR(priv->base_s); 252 + 253 + ret = rzt2h_icu_parse_interrupts(priv, node); 254 + if (ret) 255 + return dev_err_probe(dev, ret, "cannot parse interrupts: %d\n", ret); 256 + 257 + ret = devm_pm_runtime_enable(dev); 258 + if (ret) 259 + return dev_err_probe(dev, ret, "devm_pm_runtime_enable failed: %d\n", ret); 260 + 261 + ret = pm_runtime_resume_and_get(dev); 262 + if (ret) 263 + return dev_err_probe(dev, ret, "pm_runtime_resume_and_get failed: %d\n", ret); 264 + 265 + irq_domain = irq_domain_create_hierarchy(parent_domain, 0, RZT2H_ICU_NUM_IRQ, 266 + dev_fwnode(dev), &rzt2h_icu_domain_ops, priv); 267 + if (!irq_domain) { 268 + pm_runtime_put(dev); 269 + return -ENOMEM; 270 + } 271 + 272 + return 0; 273 + } 274 + 275 + IRQCHIP_PLATFORM_DRIVER_BEGIN(rzt2h_icu) 276 + IRQCHIP_MATCH("renesas,r9a09g077-icu", rzt2h_icu_init) 277 + IRQCHIP_PLATFORM_DRIVER_END(rzt2h_icu) 278 + MODULE_AUTHOR("Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>"); 279 + MODULE_DESCRIPTION("Renesas RZ/T2H ICU Driver"); 280 + MODULE_LICENSE("GPL");
+58 -3
drivers/irqchip/irq-renesas-rzv2h.c
··· 20 20 #include <linux/pm_runtime.h> 21 21 #include <linux/reset.h> 22 22 #include <linux/spinlock.h> 23 + #include <linux/syscore_ops.h> 23 24 24 25 /* DT "interrupts" indexes */ 25 26 #define ICU_IRQ_START 1 ··· 91 90 #define ICU_RZV2H_TSSEL_MAX_VAL 0x55 92 91 93 92 /** 93 + * struct rzv2h_irqc_reg_cache - registers cache (necessary for suspend/resume) 94 + * @nitsr: ICU_NITSR register 95 + * @iitsr: ICU_IITSR register 96 + * @titsr: ICU_TITSR registers 97 + */ 98 + struct rzv2h_irqc_reg_cache { 99 + u32 nitsr; 100 + u32 iitsr; 101 + u32 titsr[2]; 102 + }; 103 + 104 + /** 94 105 * struct rzv2h_hw_info - Interrupt Control Unit controller hardware info structure. 95 106 * @tssel_lut: TINT lookup table 96 107 * @t_offs: TINT offset ··· 131 118 * @fwspec: IRQ firmware specific data 132 119 * @lock: Lock to serialize access to hardware registers 133 120 * @info: Pointer to struct rzv2h_hw_info 121 + * @cache: Registers cache for suspend/resume 134 122 */ 135 - struct rzv2h_icu_priv { 123 + static struct rzv2h_icu_priv { 136 124 void __iomem *base; 137 125 struct irq_fwspec fwspec[ICU_NUM_IRQ]; 138 126 raw_spinlock_t lock; 139 127 const struct rzv2h_hw_info *info; 140 - }; 128 + struct rzv2h_irqc_reg_cache cache; 129 + } *rzv2h_icu_data; 141 130 142 131 void rzv2h_icu_register_dma_req(struct platform_device *icu_dev, u8 dmac_index, u8 dmac_channel, 143 132 u16 req_no) ··· 434 419 return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH); 435 420 } 436 421 422 + static int rzv2h_irqc_irq_suspend(void *data) 423 + { 424 + struct rzv2h_irqc_reg_cache *cache = &rzv2h_icu_data->cache; 425 + void __iomem *base = rzv2h_icu_data->base; 426 + 427 + cache->nitsr = readl_relaxed(base + ICU_NITSR); 428 + cache->iitsr = readl_relaxed(base + ICU_IITSR); 429 + for (unsigned int i = 0; i < 2; i++) 430 + cache->titsr[i] = readl_relaxed(base + rzv2h_icu_data->info->t_offs + ICU_TITSR(i)); 431 + 432 + return 0; 433 + } 434 + 435 + static void rzv2h_irqc_irq_resume(void *data) 436 + { 437 + struct rzv2h_irqc_reg_cache *cache = &rzv2h_icu_data->cache; 438 + void __iomem *base = rzv2h_icu_data->base; 439 + 440 + /* 441 + * Restore only interrupt type. TSSRx will be restored at the 442 + * request of pin controller to avoid spurious interrupts due 443 + * to invalid PIN states. 444 + */ 445 + for (unsigned int i = 0; i < 2; i++) 446 + writel_relaxed(cache->titsr[i], base + rzv2h_icu_data->info->t_offs + ICU_TITSR(i)); 447 + writel_relaxed(cache->iitsr, base + ICU_IITSR); 448 + writel_relaxed(cache->nitsr, base + ICU_NITSR); 449 + } 450 + 451 + static const struct syscore_ops rzv2h_irqc_syscore_ops = { 452 + .suspend = rzv2h_irqc_irq_suspend, 453 + .resume = rzv2h_irqc_irq_resume, 454 + }; 455 + 456 + static struct syscore rzv2h_irqc_syscore = { 457 + .ops = &rzv2h_irqc_syscore_ops, 458 + }; 459 + 437 460 static const struct irq_chip rzv2h_icu_chip = { 438 461 .name = "rzv2h-icu", 439 462 .irq_eoi = rzv2h_icu_eoi, ··· 555 502 { 556 503 struct irq_domain *irq_domain, *parent_domain; 557 504 struct device_node *node = pdev->dev.of_node; 558 - struct rzv2h_icu_priv *rzv2h_icu_data; 559 505 struct reset_control *resetn; 560 506 int ret; 561 507 ··· 611 559 } 612 560 613 561 rzv2h_icu_data->info = hw_info; 562 + 563 + register_syscore(&rzv2h_irqc_syscore); 614 564 615 565 /* 616 566 * coccicheck complains about a missing put_device call before returning, but it's a false ··· 677 623 678 624 IRQCHIP_PLATFORM_DRIVER_BEGIN(rzv2h_icu) 679 625 IRQCHIP_MATCH("renesas,r9a09g047-icu", rzg3e_icu_probe) 626 + IRQCHIP_MATCH("renesas,r9a09g056-icu", rzv2h_icu_probe) 680 627 IRQCHIP_MATCH("renesas,r9a09g057-icu", rzv2h_icu_probe) 681 628 IRQCHIP_PLATFORM_DRIVER_END(rzv2h_icu) 682 629 MODULE_AUTHOR("Fabrizio Castro <fabrizio.castro.jz@renesas.com>");
+10
drivers/irqchip/irq-riscv-aplic-direct.c
··· 8 8 #include <linux/bitfield.h> 9 9 #include <linux/bitops.h> 10 10 #include <linux/cpu.h> 11 + #include <linux/cpumask.h> 11 12 #include <linux/interrupt.h> 12 13 #include <linux/irqchip.h> 13 14 #include <linux/irqchip/chained_irq.h> ··· 170 169 171 170 /* Delivery must be set to 1 for interrupt triggering */ 172 171 writel(de, idc->regs + APLIC_IDC_IDELIVERY); 172 + } 173 + 174 + void aplic_direct_restore_states(struct aplic_priv *priv) 175 + { 176 + struct aplic_direct *direct = container_of(priv, struct aplic_direct, priv); 177 + int cpu; 178 + 179 + for_each_cpu(cpu, &direct->lmask) 180 + aplic_idc_set_delivery(per_cpu_ptr(&aplic_idcs, cpu), true); 173 181 } 174 182 175 183 static int aplic_direct_dying_cpu(unsigned int cpu)
+169 -1
drivers/irqchip/irq-riscv-aplic-main.c
··· 12 12 #include <linux/of.h> 13 13 #include <linux/of_irq.h> 14 14 #include <linux/platform_device.h> 15 + #include <linux/pm_domain.h> 16 + #include <linux/pm_runtime.h> 15 17 #include <linux/printk.h> 18 + #include <linux/syscore_ops.h> 16 19 17 20 #include "irq-riscv-aplic-main.h" 21 + 22 + static LIST_HEAD(aplics); 23 + 24 + static void aplic_restore_states(struct aplic_priv *priv) 25 + { 26 + struct aplic_saved_regs *saved_regs = &priv->saved_hw_regs; 27 + struct aplic_src_ctrl *srcs; 28 + void __iomem *regs; 29 + u32 nr_irqs, i; 30 + 31 + regs = priv->regs; 32 + writel(saved_regs->domaincfg, regs + APLIC_DOMAINCFG); 33 + #ifdef CONFIG_RISCV_M_MODE 34 + writel(saved_regs->msiaddr, regs + APLIC_xMSICFGADDR); 35 + writel(saved_regs->msiaddrh, regs + APLIC_xMSICFGADDRH); 36 + #endif 37 + /* 38 + * The sourcecfg[i] has to be restored prior to the target[i], interrupt-pending and 39 + * interrupt-enable bits. The AIA specification states that "Whenever interrupt source i is 40 + * inactive in an interrupt domain, the corresponding interrupt-pending and interrupt-enable 41 + * bits within the domain are read-only zeros, and register target[i] is also read-only 42 + * zero." 43 + */ 44 + nr_irqs = priv->nr_irqs; 45 + for (i = 0; i < nr_irqs; i++) { 46 + srcs = &priv->saved_hw_regs.srcs[i]; 47 + writel(srcs->sourcecfg, regs + APLIC_SOURCECFG_BASE + i * sizeof(u32)); 48 + writel(srcs->target, regs + APLIC_TARGET_BASE + i * sizeof(u32)); 49 + } 50 + 51 + for (i = 0; i <= nr_irqs; i += 32) { 52 + srcs = &priv->saved_hw_regs.srcs[i]; 53 + writel(-1U, regs + APLIC_CLRIE_BASE + (i / 32) * sizeof(u32)); 54 + writel(srcs->ie, regs + APLIC_SETIE_BASE + (i / 32) * sizeof(u32)); 55 + 56 + /* Re-trigger the interrupts if it forwards interrupts to target harts by MSIs */ 57 + if (!priv->nr_idcs) 58 + writel(readl(regs + APLIC_CLRIP_BASE + (i / 32) * sizeof(u32)), 59 + regs + APLIC_SETIP_BASE + (i / 32) * sizeof(u32)); 60 + } 61 + 62 + if (priv->nr_idcs) 63 + aplic_direct_restore_states(priv); 64 + } 65 + 66 + static void aplic_save_states(struct aplic_priv *priv) 67 + { 68 + struct aplic_src_ctrl *srcs; 69 + void __iomem *regs; 70 + u32 i, nr_irqs; 71 + 72 + regs = priv->regs; 73 + nr_irqs = priv->nr_irqs; 74 + /* The valid interrupt source IDs range from 1 to N, where N is priv->nr_irqs */ 75 + for (i = 0; i < nr_irqs; i++) { 76 + srcs = &priv->saved_hw_regs.srcs[i]; 77 + srcs->target = readl(regs + APLIC_TARGET_BASE + i * sizeof(u32)); 78 + 79 + if (i % 32) 80 + continue; 81 + 82 + srcs->ie = readl(regs + APLIC_SETIE_BASE + (i / 32) * sizeof(u32)); 83 + } 84 + 85 + /* Save the nr_irqs bit if needed */ 86 + if (!(nr_irqs % 32)) { 87 + srcs = &priv->saved_hw_regs.srcs[nr_irqs]; 88 + srcs->ie = readl(regs + APLIC_SETIE_BASE + (nr_irqs / 32) * sizeof(u32)); 89 + } 90 + } 91 + 92 + static int aplic_syscore_suspend(void *data) 93 + { 94 + struct aplic_priv *priv; 95 + 96 + list_for_each_entry(priv, &aplics, head) 97 + aplic_save_states(priv); 98 + 99 + return 0; 100 + } 101 + 102 + static void aplic_syscore_resume(void *data) 103 + { 104 + struct aplic_priv *priv; 105 + 106 + list_for_each_entry(priv, &aplics, head) 107 + aplic_restore_states(priv); 108 + } 109 + 110 + static struct syscore_ops aplic_syscore_ops = { 111 + .suspend = aplic_syscore_suspend, 112 + .resume = aplic_syscore_resume, 113 + }; 114 + 115 + static struct syscore aplic_syscore = { 116 + .ops = &aplic_syscore_ops, 117 + }; 118 + 119 + static int aplic_pm_notifier(struct notifier_block *nb, unsigned long action, void *data) 120 + { 121 + struct aplic_priv *priv = container_of(nb, struct aplic_priv, genpd_nb); 122 + 123 + switch (action) { 124 + case GENPD_NOTIFY_PRE_OFF: 125 + aplic_save_states(priv); 126 + break; 127 + case GENPD_NOTIFY_ON: 128 + aplic_restore_states(priv); 129 + break; 130 + default: 131 + break; 132 + } 133 + 134 + return 0; 135 + } 136 + 137 + static void aplic_pm_remove(void *data) 138 + { 139 + struct aplic_priv *priv = data; 140 + struct device *dev = priv->dev; 141 + 142 + list_del(&priv->head); 143 + if (dev->pm_domain) 144 + dev_pm_genpd_remove_notifier(dev); 145 + } 146 + 147 + static int aplic_pm_add(struct device *dev, struct aplic_priv *priv) 148 + { 149 + struct aplic_src_ctrl *srcs; 150 + int ret; 151 + 152 + srcs = devm_kzalloc(dev, (priv->nr_irqs + 1) * sizeof(*srcs), GFP_KERNEL); 153 + if (!srcs) 154 + return -ENOMEM; 155 + 156 + priv->saved_hw_regs.srcs = srcs; 157 + list_add(&priv->head, &aplics); 158 + if (dev->pm_domain) { 159 + priv->genpd_nb.notifier_call = aplic_pm_notifier; 160 + ret = dev_pm_genpd_add_notifier(dev, &priv->genpd_nb); 161 + if (ret) 162 + goto remove_head; 163 + 164 + ret = devm_pm_runtime_enable(dev); 165 + if (ret) 166 + goto remove_notifier; 167 + } 168 + 169 + return devm_add_action_or_reset(dev, aplic_pm_remove, priv); 170 + 171 + remove_notifier: 172 + dev_pm_genpd_remove_notifier(dev); 173 + remove_head: 174 + list_del(&priv->head); 175 + return ret; 176 + } 18 177 19 178 void aplic_irq_unmask(struct irq_data *d) 20 179 { ··· 219 60 sourcecfg += (d->hwirq - 1) * sizeof(u32); 220 61 writel(val, sourcecfg); 221 62 63 + priv->saved_hw_regs.srcs[d->hwirq - 1].sourcecfg = val; 64 + 222 65 return 0; 223 66 } 224 67 ··· 243 82 244 83 void aplic_init_hw_global(struct aplic_priv *priv, bool msi_mode) 245 84 { 85 + struct aplic_saved_regs *saved_regs = &priv->saved_hw_regs; 246 86 u32 val; 247 87 #ifdef CONFIG_RISCV_M_MODE 248 88 u32 valh; ··· 257 95 valh |= FIELD_PREP(APLIC_xMSICFGADDRH_HHXS, priv->msicfg.hhxs); 258 96 writel(val, priv->regs + APLIC_xMSICFGADDR); 259 97 writel(valh, priv->regs + APLIC_xMSICFGADDRH); 98 + saved_regs->msiaddr = val; 99 + saved_regs->msiaddrh = valh; 260 100 } 261 101 #endif 262 102 ··· 270 106 writel(val, priv->regs + APLIC_DOMAINCFG); 271 107 if (readl(priv->regs + APLIC_DOMAINCFG) != val) 272 108 dev_warn(priv->dev, "unable to write 0x%x in domaincfg\n", val); 109 + 110 + saved_regs->domaincfg = val; 273 111 } 274 112 275 113 static void aplic_init_hw_irqs(struct aplic_priv *priv) ··· 342 176 /* Setup initial state APLIC interrupts */ 343 177 aplic_init_hw_irqs(priv); 344 178 345 - return 0; 179 + return aplic_pm_add(dev, priv); 346 180 } 347 181 348 182 static int aplic_probe(struct platform_device *pdev) ··· 375 209 if (rc) 376 210 dev_err_probe(dev, rc, "failed to setup APLIC in %s mode\n", 377 211 msi_mode ? "MSI" : "direct"); 212 + else 213 + register_syscore(&aplic_syscore); 378 214 379 215 #ifdef CONFIG_ACPI 380 216 if (!acpi_disabled)
+19
drivers/irqchip/irq-riscv-aplic-main.h
··· 23 23 u32 lhxw; 24 24 }; 25 25 26 + struct aplic_src_ctrl { 27 + u32 sourcecfg; 28 + u32 target; 29 + u32 ie; 30 + }; 31 + 32 + struct aplic_saved_regs { 33 + u32 domaincfg; 34 + #ifdef CONFIG_RISCV_M_MODE 35 + u32 msiaddr; 36 + u32 msiaddrh; 37 + #endif 38 + struct aplic_src_ctrl *srcs; 39 + }; 40 + 26 41 struct aplic_priv { 42 + struct list_head head; 43 + struct notifier_block genpd_nb; 44 + struct aplic_saved_regs saved_hw_regs; 27 45 struct device *dev; 28 46 u32 gsi_base; 29 47 u32 nr_irqs; ··· 58 40 unsigned long *hwirq, unsigned int *type); 59 41 void aplic_init_hw_global(struct aplic_priv *priv, bool msi_mode); 60 42 int aplic_setup_priv(struct aplic_priv *priv, struct device *dev, void __iomem *regs); 43 + void aplic_direct_restore_states(struct aplic_priv *priv); 61 44 int aplic_direct_setup(struct device *dev, void __iomem *regs); 62 45 #ifdef CONFIG_RISCV_APLIC_MSI 63 46 int aplic_msi_setup(struct device *dev, void __iomem *regs);
+31 -8
drivers/irqchip/irq-riscv-imsic-early.c
··· 7 7 #define pr_fmt(fmt) "riscv-imsic: " fmt 8 8 #include <linux/acpi.h> 9 9 #include <linux/cpu.h> 10 + #include <linux/cpu_pm.h> 10 11 #include <linux/export.h> 11 12 #include <linux/interrupt.h> 12 13 #include <linux/init.h> ··· 124 123 chained_irq_exit(chip, desc); 125 124 } 126 125 127 - static int imsic_starting_cpu(unsigned int cpu) 126 + static void imsic_hw_states_init(void) 128 127 { 129 - /* Mark per-CPU IMSIC state as online */ 130 - imsic_state_online(); 131 - 132 - /* Enable per-CPU parent interrupt */ 133 - enable_percpu_irq(imsic_parent_irq, irq_get_trigger_type(imsic_parent_irq)); 134 - 135 128 /* Setup IPIs */ 136 129 imsic_ipi_starting_cpu(); 137 130 ··· 137 142 138 143 /* Enable local interrupt delivery */ 139 144 imsic_local_delivery(true); 145 + } 146 + 147 + static int imsic_starting_cpu(unsigned int cpu) 148 + { 149 + /* Mark per-CPU IMSIC state as online */ 150 + imsic_state_online(); 151 + 152 + /* Enable per-CPU parent interrupt */ 153 + enable_percpu_irq(imsic_parent_irq, irq_get_trigger_type(imsic_parent_irq)); 154 + 155 + /* Initialize the IMSIC registers to enable the interrupt delivery */ 156 + imsic_hw_states_init(); 140 157 141 158 return 0; 142 159 } ··· 163 156 164 157 return 0; 165 158 } 159 + 160 + static int imsic_pm_notifier(struct notifier_block *self, unsigned long cmd, void *v) 161 + { 162 + switch (cmd) { 163 + case CPU_PM_EXIT: 164 + /* Initialize the IMSIC registers to enable the interrupt delivery */ 165 + imsic_hw_states_init(); 166 + break; 167 + } 168 + 169 + return NOTIFY_OK; 170 + } 171 + 172 + static struct notifier_block imsic_pm_notifier_block = { 173 + .notifier_call = imsic_pm_notifier, 174 + }; 166 175 167 176 static int __init imsic_early_probe(struct fwnode_handle *fwnode) 168 177 { ··· 217 194 cpuhp_setup_state(CPUHP_AP_IRQ_RISCV_IMSIC_STARTING, "irqchip/riscv/imsic:starting", 218 195 imsic_starting_cpu, imsic_dying_cpu); 219 196 220 - return 0; 197 + return cpu_pm_register_notifier(&imsic_pm_notifier_block); 221 198 } 222 199 223 200 static int __init imsic_early_dt_init(struct device_node *node, struct device_node *parent)
+45 -37
drivers/irqchip/irq-sifive-plic.c
··· 68 68 #define PLIC_QUIRK_CP100_CLAIM_REGISTER_ERRATUM 1 69 69 70 70 struct plic_priv { 71 - struct fwnode_handle *fwnode; 72 - struct cpumask lmask; 73 - struct irq_domain *irqdomain; 74 - void __iomem *regs; 75 - unsigned long plic_quirks; 76 - unsigned int nr_irqs; 77 - unsigned long *prio_save; 78 - u32 gsi_base; 79 - int acpi_plic_id; 71 + struct fwnode_handle *fwnode; 72 + struct cpumask lmask; 73 + struct irq_domain *irqdomain; 74 + void __iomem *regs; 75 + unsigned long plic_quirks; 76 + /* device interrupts + 1 to compensate for the reserved hwirq 0 */ 77 + unsigned int __private total_irqs; 78 + unsigned int irq_groups; 79 + unsigned long *prio_save; 80 + u32 gsi_base; 81 + int acpi_plic_id; 80 82 }; 81 83 82 84 struct plic_handler { ··· 93 91 u32 *enable_save; 94 92 struct plic_priv *priv; 95 93 }; 94 + 95 + /* 96 + * Macro to deal with the insanity of hardware interrupt 0 being reserved */ 97 + #define for_each_device_irq(iter, priv) \ 98 + for (unsigned int iter = 1; iter < ACCESS_PRIVATE(priv, total_irqs); iter++) 99 + 96 100 static int plic_parent_irq __ro_after_init; 97 101 static bool plic_global_setup_done __ro_after_init; 98 102 static DEFINE_PER_CPU(struct plic_handler, plic_handlers); ··· 265 257 266 258 static int plic_irq_suspend(void *data) 267 259 { 268 - struct plic_priv *priv; 260 + struct plic_priv *priv = this_cpu_ptr(&plic_handlers)->priv; 269 261 270 - priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv; 271 - 272 - /* irq ID 0 is reserved */ 273 - for (unsigned int i = 1; i < priv->nr_irqs; i++) { 274 - __assign_bit(i, priv->prio_save, 275 - readl(priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID)); 262 + for_each_device_irq(irq, priv) { 263 + __assign_bit(irq, priv->prio_save, 264 + readl(priv->regs + PRIORITY_BASE + irq * PRIORITY_PER_ID)); 276 265 } 277 266 278 267 return 0; ··· 277 272 278 273 static void plic_irq_resume(void *data) 279 274 { 280 - unsigned int i, index, cpu; 275 + struct plic_priv *priv = this_cpu_ptr(&plic_handlers)->priv; 276 + unsigned int index, cpu; 281 277 unsigned long flags; 282 278 u32 __iomem *reg; 283 - struct plic_priv *priv; 284 279 285 - priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv; 286 - 287 - /* irq ID 0 is reserved */ 288 - for (i = 1; i < priv->nr_irqs; i++) { 289 - index = BIT_WORD(i); 290 - writel((priv->prio_save[index] & BIT_MASK(i)) ? 1 : 0, 291 - priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID); 280 + for_each_device_irq(irq, priv) { 281 + index = BIT_WORD(irq); 282 + writel((priv->prio_save[index] & BIT_MASK(irq)) ? 1 : 0, 283 + priv->regs + PRIORITY_BASE + irq * PRIORITY_PER_ID); 292 284 } 293 285 294 286 for_each_present_cpu(cpu) { ··· 295 293 continue; 296 294 297 295 raw_spin_lock_irqsave(&handler->enable_lock, flags); 298 - for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) { 296 + for (unsigned int i = 0; i < priv->irq_groups; i++) { 299 297 reg = handler->enable_base + i * sizeof(u32); 300 298 writel(handler->enable_save[i], reg); 301 299 } ··· 433 431 434 432 static irq_hw_number_t cp100_get_hwirq(struct plic_handler *handler, void __iomem *claim) 435 433 { 436 - int nr_irq_groups = DIV_ROUND_UP(handler->priv->nr_irqs, 32); 434 + int nr_irq_groups = handler->priv->irq_groups; 437 435 u32 __iomem *enable = handler->enable_base; 438 436 irq_hw_number_t hwirq = 0; 439 437 u32 iso_mask; ··· 616 614 struct plic_handler *handler; 617 615 u32 nr_irqs, parent_hwirq; 618 616 struct plic_priv *priv; 619 - irq_hw_number_t hwirq; 620 617 void __iomem *regs; 621 618 int id, context_id; 622 619 u32 gsi_base; ··· 648 647 649 648 priv->fwnode = fwnode; 650 649 priv->plic_quirks = plic_quirks; 651 - priv->nr_irqs = nr_irqs; 650 + /* 651 + * The firmware provides the number of device interrupts. As 652 + * hardware interrupt 0 is reserved, the number of total interrupts 653 + * is nr_irqs + 1. 654 + */ 655 + nr_irqs++; 656 + ACCESS_PRIVATE(priv, total_irqs) = nr_irqs; 657 + /* Precalculate the number of register groups */ 658 + priv->irq_groups = DIV_ROUND_UP(nr_irqs, 32); 659 + 652 660 priv->regs = regs; 653 661 priv->gsi_base = gsi_base; 654 662 priv->acpi_plic_id = id; ··· 696 686 u32 __iomem *enable_base = priv->regs + CONTEXT_ENABLE_BASE + 697 687 i * CONTEXT_ENABLE_SIZE; 698 688 699 - for (int j = 0; j <= nr_irqs / 32; j++) 689 + for (int j = 0; j < priv->irq_groups; j++) 700 690 writel(0, enable_base + j); 701 691 } 702 692 continue; ··· 728 718 context_id * CONTEXT_ENABLE_SIZE; 729 719 handler->priv = priv; 730 720 731 - handler->enable_save = kcalloc(DIV_ROUND_UP(nr_irqs, 32), 732 - sizeof(*handler->enable_save), GFP_KERNEL); 721 + handler->enable_save = kcalloc(priv->irq_groups, sizeof(*handler->enable_save), 722 + GFP_KERNEL); 733 723 if (!handler->enable_save) { 734 724 error = -ENOMEM; 735 725 goto fail_cleanup_contexts; 736 726 } 737 727 done: 738 - for (hwirq = 1; hwirq <= nr_irqs; hwirq++) { 728 + for_each_device_irq(hwirq, priv) { 739 729 plic_toggle(handler, hwirq, 0); 740 - writel(1, priv->regs + PRIORITY_BASE + 741 - hwirq * PRIORITY_PER_ID); 730 + writel(1, priv->regs + PRIORITY_BASE + hwirq * PRIORITY_PER_ID); 742 731 } 743 732 nr_handlers++; 744 733 } 745 734 746 - priv->irqdomain = irq_domain_create_linear(fwnode, nr_irqs + 1, 747 - &plic_irqdomain_ops, priv); 735 + priv->irqdomain = irq_domain_create_linear(fwnode, nr_irqs, &plic_irqdomain_ops, priv); 748 736 if (WARN_ON(!priv->irqdomain)) { 749 737 error = -ENOMEM; 750 738 goto fail_cleanup_contexts;
+36 -18
drivers/irqchip/irq-ti-sci-intr.c
··· 61 61 { 62 62 struct ti_sci_intr_irq_domain *intr = domain->host_data; 63 63 64 - if (fwspec->param_count != 1) 65 - return -EINVAL; 64 + if (intr->type) { 65 + /* Global interrupt-type */ 66 + if (fwspec->param_count != 1) 67 + return -EINVAL; 66 68 67 - *hwirq = fwspec->param[0]; 68 - *type = intr->type; 69 + *hwirq = fwspec->param[0]; 70 + *type = intr->type; 71 + } else { 72 + /* Per-Line interrupt-type */ 73 + if (fwspec->param_count != 2) 74 + return -EINVAL; 69 75 76 + *hwirq = fwspec->param[0]; 77 + *type = fwspec->param[1]; 78 + } 70 79 return 0; 71 80 } 72 81 ··· 137 128 * @domain: Pointer to the interrupt router IRQ domain 138 129 * @virq: Corresponding Linux virtual IRQ number 139 130 * @hwirq: Corresponding hwirq for the IRQ within this IRQ domain 131 + * @hwirq_type: Corresponding hwirq trigger type for the IRQ within this IRQ domain 140 132 * 141 133 * Returns intr output irq if all went well else appropriate error pointer. 142 134 */ 143 - static int ti_sci_intr_alloc_parent_irq(struct irq_domain *domain, 144 - unsigned int virq, u32 hwirq) 135 + static int ti_sci_intr_alloc_parent_irq(struct irq_domain *domain, unsigned int virq, 136 + u32 hwirq, u32 hwirq_type) 145 137 { 146 138 struct ti_sci_intr_irq_domain *intr = domain->host_data; 147 139 struct device_node *parent_node; ··· 166 156 fwspec.param_count = 3; 167 157 fwspec.param[0] = 0; /* SPI */ 168 158 fwspec.param[1] = p_hwirq - 32; /* SPI offset */ 169 - fwspec.param[2] = intr->type; 159 + fwspec.param[2] = hwirq_type; 170 160 } else { 171 161 /* Parent is Interrupt Router */ 172 - fwspec.param_count = 1; 173 - fwspec.param[0] = p_hwirq; 162 + u32 parent_trigger_type; 163 + 164 + if (!of_property_read_u32(parent_node, "ti,intr-trigger-type", 165 + &parent_trigger_type)) { 166 + /* Parent has global trigger type */ 167 + fwspec.param_count = 1; 168 + fwspec.param[0] = p_hwirq; 169 + } else { 170 + /* Parent supports per-line trigger types */ 171 + fwspec.param_count = 2; 172 + fwspec.param[0] = p_hwirq; 173 + fwspec.param[1] = hwirq_type; 174 + } 174 175 } 175 176 176 177 err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec); ··· 217 196 void *data) 218 197 { 219 198 struct irq_fwspec *fwspec = data; 199 + unsigned int hwirq_type; 220 200 unsigned long hwirq; 221 - unsigned int flags; 222 201 int err, out_irq; 223 202 224 - err = ti_sci_intr_irq_domain_translate(domain, fwspec, &hwirq, &flags); 203 + err = ti_sci_intr_irq_domain_translate(domain, fwspec, &hwirq, &hwirq_type); 225 204 if (err) 226 205 return err; 227 206 228 - out_irq = ti_sci_intr_alloc_parent_irq(domain, virq, hwirq); 207 + out_irq = ti_sci_intr_alloc_parent_irq(domain, virq, hwirq, hwirq_type); 229 208 if (out_irq < 0) 230 209 return out_irq; 231 210 ··· 268 247 return -ENOMEM; 269 248 270 249 intr->dev = dev; 271 - ret = of_property_read_u32(dev_of_node(dev), "ti,intr-trigger-type", 272 - &intr->type); 273 - if (ret) { 274 - dev_err(dev, "missing ti,intr-trigger-type property\n"); 275 - return -EINVAL; 276 - } 250 + 251 + if (of_property_read_u32(dev_of_node(dev), "ti,intr-trigger-type", &intr->type)) 252 + intr->type = IRQ_TYPE_NONE; 277 253 278 254 intr->sci = devm_ti_sci_get_by_phandle(dev, "ti,sci"); 279 255 if (IS_ERR(intr->sci))
+1
drivers/soc/renesas/Kconfig
··· 423 423 config ARCH_R9A09G077 424 424 bool "ARM64 Platform support for R9A09G077 (RZ/T2H)" 425 425 default y if ARCH_RENESAS 426 + select RENESAS_RZT2H_ICU 426 427 help 427 428 This enables support for the Renesas RZ/T2H SoC variants. 428 429
+23
include/linux/irqchip/irq-renesas-rzt2h.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Renesas RZ/T2H Interrupt Control Unit (ICU) 4 + * 5 + * Copyright (C) 2025 Renesas Electronics Corporation. 6 + */ 7 + 8 + #ifndef __LINUX_IRQ_RENESAS_RZT2H 9 + #define __LINUX_IRQ_RENESAS_RZT2H 10 + 11 + #include <linux/platform_device.h> 12 + 13 + #define RZT2H_ICU_DMAC_REQ_NO_DEFAULT 0x3ff 14 + 15 + #ifdef CONFIG_RENESAS_RZT2H_ICU 16 + void rzt2h_icu_register_dma_req(struct platform_device *icu_dev, u8 dmac_index, u8 dmac_channel, 17 + u16 req_no); 18 + #else 19 + static inline void rzt2h_icu_register_dma_req(struct platform_device *icu_dev, u8 dmac_index, 20 + u8 dmac_channel, u16 req_no) { } 21 + #endif 22 + 23 + #endif /* __LINUX_IRQ_RENESAS_RZT2H */