mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/
synced 2026-04-05 00:07:48 -04:00
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
...
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/interrupt-controller/renesas,r9a09g077-icu.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas RZ/{T2H,N2H} Interrupt Controller
|
||||
|
||||
maintainers:
|
||||
- Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/interrupt-controller.yaml#
|
||||
|
||||
description:
|
||||
The Interrupt Controller (ICU) handles software-triggered interrupts
|
||||
(INTCPU), external interrupts (IRQ and SEI), error interrupts and DMAC
|
||||
requests.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: renesas,r9a09g077-icu # RZ/T2H
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,r9a09g087-icu # RZ/N2H
|
||||
- const: renesas,r9a09g077-icu
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: Non-safety registers (INTCPU0-13, IRQ0-13)
|
||||
- description: Safety registers (INTCPU14-15, IRQ14-15, SEI)
|
||||
|
||||
'#interrupt-cells':
|
||||
description: The first cell is the SPI number of the interrupt, as per user
|
||||
manual. The second cell is used to specify the flag.
|
||||
const: 2
|
||||
|
||||
'#address-cells':
|
||||
const: 0
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: Software interrupt 0
|
||||
- description: Software interrupt 1
|
||||
- description: Software interrupt 2
|
||||
- description: Software interrupt 3
|
||||
- description: Software interrupt 4
|
||||
- description: Software interrupt 5
|
||||
- description: Software interrupt 6
|
||||
- description: Software interrupt 7
|
||||
- description: Software interrupt 8
|
||||
- description: Software interrupt 9
|
||||
- description: Software interrupt 10
|
||||
- description: Software interrupt 11
|
||||
- description: Software interrupt 12
|
||||
- description: Software interrupt 13
|
||||
- description: Software interrupt 14
|
||||
- description: Software interrupt 15
|
||||
- description: External pin interrupt 0
|
||||
- description: External pin interrupt 1
|
||||
- description: External pin interrupt 2
|
||||
- description: External pin interrupt 3
|
||||
- description: External pin interrupt 4
|
||||
- description: External pin interrupt 5
|
||||
- description: External pin interrupt 6
|
||||
- description: External pin interrupt 7
|
||||
- description: External pin interrupt 8
|
||||
- description: External pin interrupt 9
|
||||
- description: External pin interrupt 10
|
||||
- description: External pin interrupt 11
|
||||
- description: External pin interrupt 12
|
||||
- description: External pin interrupt 13
|
||||
- description: External pin interrupt 14
|
||||
- description: External pin interrupt 15
|
||||
- description: System error interrupt
|
||||
- description: Cortex-A55 error event 0
|
||||
- description: Cortex-A55 error event 1
|
||||
- description: Cortex-R52 CPU 0 error event 0
|
||||
- description: Cortex-R52 CPU 0 error event 1
|
||||
- description: Cortex-R52 CPU 1 error event 0
|
||||
- description: Cortex-R52 CPU 1 error event 1
|
||||
- description: Peripherals error event 0
|
||||
- description: Peripherals error event 1
|
||||
- description: DSMIF error event 0
|
||||
- description: DSMIF error event 1
|
||||
- description: ENCIF error event 0
|
||||
- description: ENCIF error event 1
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: intcpu0
|
||||
- const: intcpu1
|
||||
- const: intcpu2
|
||||
- const: intcpu3
|
||||
- const: intcpu4
|
||||
- const: intcpu5
|
||||
- const: intcpu6
|
||||
- const: intcpu7
|
||||
- const: intcpu8
|
||||
- const: intcpu9
|
||||
- const: intcpu10
|
||||
- const: intcpu11
|
||||
- const: intcpu12
|
||||
- const: intcpu13
|
||||
- const: intcpu14
|
||||
- const: intcpu15
|
||||
- const: irq0
|
||||
- const: irq1
|
||||
- const: irq2
|
||||
- const: irq3
|
||||
- const: irq4
|
||||
- const: irq5
|
||||
- const: irq6
|
||||
- const: irq7
|
||||
- const: irq8
|
||||
- const: irq9
|
||||
- const: irq10
|
||||
- const: irq11
|
||||
- const: irq12
|
||||
- const: irq13
|
||||
- const: irq14
|
||||
- const: irq15
|
||||
- const: sei
|
||||
- const: ca55-err0
|
||||
- const: ca55-err1
|
||||
- const: cr520-err0
|
||||
- const: cr520-err1
|
||||
- const: cr521-err0
|
||||
- const: cr521-err1
|
||||
- const: peri-err0
|
||||
- const: peri-err1
|
||||
- const: dsmif-err0
|
||||
- const: dsmif-err1
|
||||
- const: encif-err0
|
||||
- const: encif-err1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#interrupt-cells'
|
||||
- '#address-cells'
|
||||
- interrupt-controller
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- clocks
|
||||
- power-domains
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h>
|
||||
|
||||
icu: interrupt-controller@802a0000 {
|
||||
compatible = "renesas,r9a09g077-icu";
|
||||
reg = <0x802a0000 0x10000>,
|
||||
<0x812a0000 0x50>;
|
||||
#interrupt-cells = <2>;
|
||||
#address-cells = <0>;
|
||||
interrupt-controller;
|
||||
interrupts = <GIC_SPI 0 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 1 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 2 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 3 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 4 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 5 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 6 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 7 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 8 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 9 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 10 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 11 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 12 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 13 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 14 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 15 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 16 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 17 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 18 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 19 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 20 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 22 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 23 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 24 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 25 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 26 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 27 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 406 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 407 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 408 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 409 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 410 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 411 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 412 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 413 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 414 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 415 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 416 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 417 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 418 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-names = "intcpu0", "intcpu1", "intcpu2",
|
||||
"intcpu3", "intcpu4", "intcpu5",
|
||||
"intcpu6", "intcpu7", "intcpu8",
|
||||
"intcpu9", "intcpu10", "intcpu11",
|
||||
"intcpu12", "intcpu13", "intcpu14",
|
||||
"intcpu15",
|
||||
"irq0", "irq1", "irq2", "irq3",
|
||||
"irq4", "irq5", "irq6", "irq7",
|
||||
"irq8", "irq9", "irq10", "irq11",
|
||||
"irq12", "irq13", "irq14", "irq15",
|
||||
"sei",
|
||||
"ca55-err0", "ca55-err1",
|
||||
"cr520-err0", "cr520-err1",
|
||||
"cr521-err0", "cr521-err1",
|
||||
"peri-err0", "peri-err1",
|
||||
"dsmif-err0", "dsmif-err1",
|
||||
"encif-err0", "encif-err1";
|
||||
clocks = <&cpg CPG_CORE R9A09G077_CLK_PCLKM>;
|
||||
power-domains = <&cpg>;
|
||||
};
|
||||
@@ -22,6 +22,7 @@ properties:
|
||||
compatible:
|
||||
enum:
|
||||
- renesas,r9a09g047-icu # RZ/G3E
|
||||
- renesas,r9a09g056-icu # RZ/V2N
|
||||
- renesas,r9a09g057-icu # RZ/V2H(P)
|
||||
|
||||
'#interrupt-cells':
|
||||
|
||||
@@ -108,7 +108,9 @@ properties:
|
||||
riscv,ndev:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
Specifies how many external interrupts are supported by this controller.
|
||||
Specifies how many external (device) interrupts are supported by this
|
||||
controller. Note that source 0 is reserved in PLIC, so the valid
|
||||
interrupt sources are 1 to riscv,ndev inclusive.
|
||||
|
||||
clocks: true
|
||||
|
||||
|
||||
@@ -15,8 +15,7 @@ allOf:
|
||||
description: |
|
||||
The Interrupt Router (INTR) module provides a mechanism to mux M
|
||||
interrupt inputs to N interrupt outputs, where all M inputs are selectable
|
||||
to be driven per N output. An Interrupt Router can either handle edge
|
||||
triggered or level triggered interrupts and that is fixed in hardware.
|
||||
to be driven per N output.
|
||||
|
||||
Interrupt Router
|
||||
+----------------------+
|
||||
@@ -64,9 +63,14 @@ properties:
|
||||
interrupt-controller: true
|
||||
|
||||
'#interrupt-cells':
|
||||
const: 1
|
||||
enum: [1, 2]
|
||||
description: |
|
||||
The 1st cell should contain interrupt router input hw number.
|
||||
Number of cells in interrupt specifier. Depends on ti,intr-trigger-type:
|
||||
- If ti,intr-trigger-type is present: must be 1
|
||||
The 1st cell should contain interrupt router input hw number.
|
||||
- If ti,intr-trigger-type is absent: must be 2
|
||||
The 1st cell should contain interrupt router input hw number.
|
||||
The 2nd cell should contain interrupt trigger type (preserved by router).
|
||||
|
||||
ti,interrupt-ranges:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-matrix
|
||||
@@ -82,9 +86,22 @@ properties:
|
||||
- description: |
|
||||
"limit" specifies the limit for translation
|
||||
|
||||
if:
|
||||
required:
|
||||
- ti,intr-trigger-type
|
||||
then:
|
||||
properties:
|
||||
'#interrupt-cells':
|
||||
const: 1
|
||||
description: Interrupt ID only. Interrupt type is specified globally
|
||||
else:
|
||||
properties:
|
||||
'#interrupt-cells':
|
||||
const: 2
|
||||
description: Interrupt ID and corresponding interrupt type
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- ti,intr-trigger-type
|
||||
- interrupt-controller
|
||||
- '#interrupt-cells'
|
||||
- ti,sci
|
||||
@@ -105,3 +122,14 @@ examples:
|
||||
ti,sci-dev-id = <131>;
|
||||
ti,interrupt-ranges = <0 360 32>;
|
||||
};
|
||||
|
||||
- |
|
||||
interrupt-controller {
|
||||
compatible = "ti,sci-intr";
|
||||
interrupt-controller;
|
||||
interrupt-parent = <&gic500>;
|
||||
#interrupt-cells = <2>;
|
||||
ti,sci = <&dmsc>;
|
||||
ti,sci-dev-id = <131>;
|
||||
ti,interrupt-ranges = <0 360 32>;
|
||||
};
|
||||
|
||||
@@ -756,6 +756,79 @@
|
||||
#power-domain-cells = <0>;
|
||||
};
|
||||
|
||||
icu: interrupt-controller@802a0000 {
|
||||
compatible = "renesas,r9a09g077-icu";
|
||||
reg = <0 0x802a0000 0 0x10000>,
|
||||
<0 0x812a0000 0 0x50>;
|
||||
#interrupt-cells = <2>;
|
||||
#address-cells = <0>;
|
||||
interrupt-controller;
|
||||
interrupts = <GIC_SPI 0 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 1 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 2 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 3 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 4 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 5 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 6 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 7 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 8 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 9 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 10 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 11 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 12 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 13 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 14 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 15 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 16 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 17 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 18 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 19 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 20 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 22 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 23 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 24 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 25 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 26 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 27 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 406 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 407 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 408 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 409 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 410 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 411 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 412 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 413 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 414 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 415 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 416 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 417 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 418 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-names = "intcpu0", "intcpu1", "intcpu2",
|
||||
"intcpu3", "intcpu4", "intcpu5",
|
||||
"intcpu6", "intcpu7", "intcpu8",
|
||||
"intcpu9", "intcpu10", "intcpu11",
|
||||
"intcpu12", "intcpu13", "intcpu14",
|
||||
"intcpu15",
|
||||
"irq0", "irq1", "irq2", "irq3",
|
||||
"irq4", "irq5", "irq6", "irq7",
|
||||
"irq8", "irq9", "irq10", "irq11",
|
||||
"irq12", "irq13", "irq14", "irq15",
|
||||
"sei",
|
||||
"ca55-err0", "ca55-err1",
|
||||
"cr520-err0", "cr520-err1",
|
||||
"cr521-err0", "cr521-err1",
|
||||
"peri-err0", "peri-err1",
|
||||
"dsmif-err0", "dsmif-err1",
|
||||
"encif-err0", "encif-err1";
|
||||
clocks = <&cpg CPG_CORE R9A09G077_CLK_PCLKM>;
|
||||
power-domains = <&cpg>;
|
||||
};
|
||||
|
||||
pinctrl: pinctrl@802c0000 {
|
||||
compatible = "renesas,r9a09g077-pinctrl";
|
||||
reg = <0 0x802c0000 0 0x10000>,
|
||||
|
||||
@@ -759,6 +759,79 @@
|
||||
#power-domain-cells = <0>;
|
||||
};
|
||||
|
||||
icu: interrupt-controller@802a0000 {
|
||||
compatible = "renesas,r9a09g087-icu", "renesas,r9a09g077-icu";
|
||||
reg = <0 0x802a0000 0 0x10000>,
|
||||
<0 0x812a0000 0 0x50>;
|
||||
#interrupt-cells = <2>;
|
||||
#address-cells = <0>;
|
||||
interrupt-controller;
|
||||
interrupts = <GIC_SPI 0 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 1 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 2 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 3 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 4 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 5 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 6 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 7 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 8 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 9 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 10 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 11 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 12 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 13 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 14 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 15 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 16 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 17 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 18 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 19 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 20 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 21 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 22 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 23 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 24 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 25 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 26 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 27 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 406 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 407 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 408 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 409 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 410 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 411 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 412 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 413 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 414 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 415 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 416 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 417 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 418 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-names = "intcpu0", "intcpu1", "intcpu2",
|
||||
"intcpu3", "intcpu4", "intcpu5",
|
||||
"intcpu6", "intcpu7", "intcpu8",
|
||||
"intcpu9", "intcpu10", "intcpu11",
|
||||
"intcpu12", "intcpu13", "intcpu14",
|
||||
"intcpu15",
|
||||
"irq0", "irq1", "irq2", "irq3",
|
||||
"irq4", "irq5", "irq6", "irq7",
|
||||
"irq8", "irq9", "irq10", "irq11",
|
||||
"irq12", "irq13", "irq14", "irq15",
|
||||
"sei",
|
||||
"ca55-err0", "ca55-err1",
|
||||
"cr520-err0", "cr520-err1",
|
||||
"cr521-err0", "cr521-err1",
|
||||
"peri-err0", "peri-err1",
|
||||
"dsmif-err0", "dsmif-err1",
|
||||
"encif-err0", "encif-err1";
|
||||
clocks = <&cpg CPG_CORE R9A09G087_CLK_PCLKM>;
|
||||
power-domains = <&cpg>;
|
||||
};
|
||||
|
||||
pinctrl: pinctrl@802c0000 {
|
||||
compatible = "renesas,r9a09g087-pinctrl";
|
||||
reg = <0 0x802c0000 0 0x10000>,
|
||||
|
||||
@@ -297,6 +297,14 @@ config RENESAS_RZG2L_IRQC
|
||||
Enable support for the Renesas RZ/G2L (and alike SoC) Interrupt Controller
|
||||
for external devices.
|
||||
|
||||
config RENESAS_RZT2H_ICU
|
||||
bool "Renesas RZ/{T2H,N2H} ICU support" if COMPILE_TEST
|
||||
select GENERIC_IRQ_CHIP
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
help
|
||||
Enable support for the Renesas RZ/{T2H,N2H} Interrupt Controller
|
||||
(ICU).
|
||||
|
||||
config RENESAS_RZV2H_ICU
|
||||
bool "Renesas RZ/V2H(P) ICU support" if COMPILE_TEST
|
||||
select GENERIC_IRQ_CHIP
|
||||
@@ -698,7 +706,7 @@ config IRQ_LOONGARCH_CPU
|
||||
|
||||
config LOONGSON_LIOINTC
|
||||
bool "Loongson Local I/O Interrupt Controller"
|
||||
depends on MACH_LOONGSON64
|
||||
depends on MACH_LOONGSON64 || LOONGARCH
|
||||
default y
|
||||
select IRQ_DOMAIN
|
||||
select GENERIC_IRQ_CHIP
|
||||
@@ -708,7 +716,6 @@ config LOONGSON_LIOINTC
|
||||
config LOONGSON_EIOINTC
|
||||
bool "Loongson Extend I/O Interrupt Controller"
|
||||
depends on LOONGARCH
|
||||
depends on MACH_LOONGSON64
|
||||
default MACH_LOONGSON64
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
select GENERIC_IRQ_CHIP
|
||||
@@ -726,7 +733,7 @@ config LOONGSON_HTPIC
|
||||
|
||||
config LOONGSON_HTVEC
|
||||
bool "Loongson HyperTransport Interrupt Vector Controller"
|
||||
depends on MACH_LOONGSON64
|
||||
depends on MACH_LOONGSON64 || LOONGARCH
|
||||
default MACH_LOONGSON64
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
help
|
||||
@@ -734,7 +741,7 @@ config LOONGSON_HTVEC
|
||||
|
||||
config LOONGSON_PCH_PIC
|
||||
bool "Loongson PCH PIC Controller"
|
||||
depends on MACH_LOONGSON64
|
||||
depends on MACH_LOONGSON64 || LOONGARCH
|
||||
default MACH_LOONGSON64
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
select IRQ_FASTEOI_HIERARCHY_HANDLERS
|
||||
@@ -743,7 +750,7 @@ config LOONGSON_PCH_PIC
|
||||
|
||||
config LOONGSON_PCH_MSI
|
||||
bool "Loongson PCH MSI Controller"
|
||||
depends on MACH_LOONGSON64
|
||||
depends on MACH_LOONGSON64 || LOONGARCH
|
||||
depends on PCI
|
||||
default MACH_LOONGSON64
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
@@ -755,7 +762,7 @@ config LOONGSON_PCH_MSI
|
||||
config LOONGSON_PCH_LPC
|
||||
bool "Loongson PCH LPC Controller"
|
||||
depends on LOONGARCH
|
||||
depends on MACH_LOONGSON64
|
||||
depends on MACH_LOONGSON64 || LOONGARCH
|
||||
default MACH_LOONGSON64
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
help
|
||||
|
||||
@@ -54,6 +54,7 @@ obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o
|
||||
obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o
|
||||
obj-$(CONFIG_RENESAS_RZA1_IRQC) += irq-renesas-rza1.o
|
||||
obj-$(CONFIG_RENESAS_RZG2L_IRQC) += irq-renesas-rzg2l.o
|
||||
obj-$(CONFIG_RENESAS_RZT2H_ICU) += irq-renesas-rzt2h.o
|
||||
obj-$(CONFIG_RENESAS_RZV2H_ICU) += irq-renesas-rzv2h.o
|
||||
obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o
|
||||
obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o
|
||||
|
||||
@@ -109,9 +109,11 @@ static int __init aclint_sswi_probe(struct fwnode_handle *fwnode)
|
||||
if (!is_of_node(fwnode))
|
||||
return -EINVAL;
|
||||
|
||||
reg = of_iomap(to_of_node(fwnode), 0);
|
||||
if (!reg)
|
||||
return -ENOMEM;
|
||||
reg = of_io_request_and_map(to_of_node(fwnode), 0, NULL);
|
||||
if (IS_ERR(reg)) {
|
||||
pr_err("%pfwP: Failed to map MMIO region\n", fwnode);
|
||||
return PTR_ERR(reg);
|
||||
}
|
||||
|
||||
/* Parse SSWI setting */
|
||||
rc = aclint_sswi_parse_irq(fwnode, reg);
|
||||
|
||||
@@ -104,11 +104,10 @@ static void aspeed_scu_ic_irq_handler_split(struct irq_desc *desc)
|
||||
struct aspeed_scu_ic *scu_ic = irq_desc_get_handler_data(desc);
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
unsigned long bit, enabled, max, status;
|
||||
unsigned int sts, mask;
|
||||
unsigned int sts;
|
||||
|
||||
chained_irq_enter(chip, desc);
|
||||
|
||||
mask = scu_ic->irq_enable;
|
||||
sts = readl(scu_ic->base + scu_ic->isr);
|
||||
enabled = sts & scu_ic->irq_enable;
|
||||
sts = readl(scu_ic->base + scu_ic->isr);
|
||||
|
||||
@@ -902,7 +902,7 @@ static int gicv5_its_alloc_eventid(struct gicv5_its_dev *its_dev, msi_alloc_info
|
||||
event_id_base = info->hwirq;
|
||||
|
||||
if (event_id_base >= its_dev->num_events) {
|
||||
pr_err("EventID ouside of ITT range; cannot allocate an ITT entry!\n");
|
||||
pr_err("EventID outside of ITT range; cannot allocate an ITT entry!\n");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -58,11 +58,13 @@ struct avecintc_data {
|
||||
|
||||
static inline void avecintc_enable(void)
|
||||
{
|
||||
#ifdef CONFIG_MACH_LOONGSON64
|
||||
u64 value;
|
||||
|
||||
value = iocsr_read64(LOONGARCH_IOCSR_MISC_FUNC);
|
||||
value |= IOCSR_MISC_FUNC_AVEC_EN;
|
||||
iocsr_write64(value, LOONGARCH_IOCSR_MISC_FUNC);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void avecintc_ack_irq(struct irq_data *d)
|
||||
@@ -167,7 +169,7 @@ void complete_irq_moving(void)
|
||||
struct pending_list *plist = this_cpu_ptr(&pending_list);
|
||||
struct avecintc_data *adata, *tdata;
|
||||
int cpu, vector, bias;
|
||||
uint64_t isr;
|
||||
unsigned long isr;
|
||||
|
||||
guard(raw_spinlock)(&loongarch_avec.lock);
|
||||
|
||||
@@ -177,16 +179,16 @@ void complete_irq_moving(void)
|
||||
bias = vector / VECTORS_PER_REG;
|
||||
switch (bias) {
|
||||
case 0:
|
||||
isr = csr_read64(LOONGARCH_CSR_ISR0);
|
||||
isr = csr_read(LOONGARCH_CSR_ISR0);
|
||||
break;
|
||||
case 1:
|
||||
isr = csr_read64(LOONGARCH_CSR_ISR1);
|
||||
isr = csr_read(LOONGARCH_CSR_ISR1);
|
||||
break;
|
||||
case 2:
|
||||
isr = csr_read64(LOONGARCH_CSR_ISR2);
|
||||
isr = csr_read(LOONGARCH_CSR_ISR2);
|
||||
break;
|
||||
case 3:
|
||||
isr = csr_read64(LOONGARCH_CSR_ISR3);
|
||||
isr = csr_read(LOONGARCH_CSR_ISR3);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -234,7 +236,7 @@ static void avecintc_irq_dispatch(struct irq_desc *desc)
|
||||
chained_irq_enter(chip, desc);
|
||||
|
||||
while (true) {
|
||||
unsigned long vector = csr_read64(LOONGARCH_CSR_IRR);
|
||||
unsigned long vector = csr_read(LOONGARCH_CSR_IRR);
|
||||
if (vector & IRR_INVALID_MASK)
|
||||
break;
|
||||
|
||||
|
||||
@@ -37,9 +37,9 @@
|
||||
#define EXTIOI_ENABLE_INT_ENCODE BIT(2)
|
||||
#define EXTIOI_ENABLE_CPU_ENCODE BIT(3)
|
||||
|
||||
#define VEC_REG_COUNT 4
|
||||
#define VEC_COUNT_PER_REG 64
|
||||
#define VEC_COUNT (VEC_REG_COUNT * VEC_COUNT_PER_REG)
|
||||
#define VEC_COUNT 256
|
||||
#define VEC_COUNT_PER_REG BITS_PER_LONG
|
||||
#define VEC_REG_COUNT (VEC_COUNT / BITS_PER_LONG)
|
||||
#define VEC_REG_IDX(irq_id) ((irq_id) / VEC_COUNT_PER_REG)
|
||||
#define VEC_REG_BIT(irq_id) ((irq_id) % VEC_COUNT_PER_REG)
|
||||
#define EIOINTC_ALL_ENABLE 0xffffffff
|
||||
@@ -85,11 +85,13 @@ static struct eiointc_priv *eiointc_priv[MAX_IO_PICS];
|
||||
|
||||
static void eiointc_enable(void)
|
||||
{
|
||||
#ifdef CONFIG_MACH_LOONGSON64
|
||||
uint64_t misc;
|
||||
|
||||
misc = iocsr_read64(LOONGARCH_IOCSR_MISC_FUNC);
|
||||
misc |= IOCSR_MISC_FUNC_EXT_IOI_EN;
|
||||
iocsr_write64(misc, LOONGARCH_IOCSR_MISC_FUNC);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int cpu_to_eio_node(int cpu)
|
||||
@@ -281,12 +283,34 @@ static int eiointc_router_init(unsigned int cpu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if VEC_COUNT_PER_REG == 32
|
||||
static inline unsigned long read_isr(int i)
|
||||
{
|
||||
return iocsr_read32(EIOINTC_REG_ISR + (i << 2));
|
||||
}
|
||||
|
||||
static inline void write_isr(int i, unsigned long val)
|
||||
{
|
||||
iocsr_write32(val, EIOINTC_REG_ISR + (i << 2));
|
||||
}
|
||||
#else
|
||||
static inline unsigned long read_isr(int i)
|
||||
{
|
||||
return iocsr_read64(EIOINTC_REG_ISR + (i << 3));
|
||||
}
|
||||
|
||||
static inline void write_isr(int i, unsigned long val)
|
||||
{
|
||||
iocsr_write64(val, EIOINTC_REG_ISR + (i << 3));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void eiointc_irq_dispatch(struct irq_desc *desc)
|
||||
{
|
||||
struct eiointc_ip_route *info = irq_desc_get_handler_data(desc);
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
unsigned long pending;
|
||||
bool handled = false;
|
||||
u64 pending;
|
||||
int i;
|
||||
|
||||
chained_irq_enter(chip, desc);
|
||||
@@ -299,14 +323,14 @@ static void eiointc_irq_dispatch(struct irq_desc *desc)
|
||||
* read ISR for these 64 interrupt vectors rather than all vectors
|
||||
*/
|
||||
for (i = info->start; i < info->end; i++) {
|
||||
pending = iocsr_read64(EIOINTC_REG_ISR + (i << 3));
|
||||
pending = read_isr(i);
|
||||
|
||||
/* Skip handling if pending bitmap is zero */
|
||||
if (!pending)
|
||||
continue;
|
||||
|
||||
/* Clear the IRQs */
|
||||
iocsr_write64(pending, EIOINTC_REG_ISR + (i << 3));
|
||||
write_isr(i, pending);
|
||||
while (pending) {
|
||||
int bit = __ffs(pending);
|
||||
int irq = bit + VEC_COUNT_PER_REG * i;
|
||||
|
||||
@@ -295,19 +295,19 @@ static int __init acpi_cascade_irqdomain_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init htvec_acpi_init(struct irq_domain *parent,
|
||||
struct acpi_madt_ht_pic *acpi_htvec)
|
||||
int __init htvec_acpi_init(struct irq_domain *parent, struct acpi_madt_ht_pic *acpi_htvec)
|
||||
{
|
||||
int i, ret;
|
||||
int num_parents, parent_irq[8];
|
||||
int i, ret, num_parents, parent_irq[8];
|
||||
struct fwnode_handle *domain_handle;
|
||||
phys_addr_t addr;
|
||||
|
||||
if (!acpi_htvec)
|
||||
return -EINVAL;
|
||||
|
||||
num_parents = HTVEC_MAX_PARENT_IRQ;
|
||||
addr = (phys_addr_t)acpi_htvec->address;
|
||||
|
||||
domain_handle = irq_domain_alloc_fwnode(&acpi_htvec->address);
|
||||
domain_handle = irq_domain_alloc_fwnode(&addr);
|
||||
if (!domain_handle) {
|
||||
pr_err("Unable to allocate domain handle\n");
|
||||
return -ENOMEM;
|
||||
@@ -317,9 +317,7 @@ int __init htvec_acpi_init(struct irq_domain *parent,
|
||||
for (i = 0; i < HTVEC_MAX_PARENT_IRQ; i++)
|
||||
parent_irq[i] = irq_create_mapping(parent, acpi_htvec->cascade[i]);
|
||||
|
||||
ret = htvec_init(acpi_htvec->address, acpi_htvec->size,
|
||||
num_parents, parent_irq, domain_handle);
|
||||
|
||||
ret = htvec_init(addr, acpi_htvec->size, num_parents, parent_irq, domain_handle);
|
||||
if (ret == 0)
|
||||
ret = acpi_cascade_irqdomain_init();
|
||||
else
|
||||
|
||||
@@ -394,8 +394,9 @@ static int __init acpi_cascade_irqdomain_init(void)
|
||||
|
||||
int __init liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic *acpi_liointc)
|
||||
{
|
||||
int ret;
|
||||
phys_addr_t addr = (phys_addr_t)acpi_liointc->address;
|
||||
struct fwnode_handle *domain_handle;
|
||||
int ret;
|
||||
|
||||
parent_int_map[0] = acpi_liointc->cascade_map[0];
|
||||
parent_int_map[1] = acpi_liointc->cascade_map[1];
|
||||
@@ -403,14 +404,13 @@ int __init liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic
|
||||
parent_irq[0] = irq_create_mapping(parent, acpi_liointc->cascade[0]);
|
||||
parent_irq[1] = irq_create_mapping(parent, acpi_liointc->cascade[1]);
|
||||
|
||||
domain_handle = irq_domain_alloc_fwnode(&acpi_liointc->address);
|
||||
domain_handle = irq_domain_alloc_fwnode(&addr);
|
||||
if (!domain_handle) {
|
||||
pr_err("Unable to allocate domain handle\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = liointc_init(acpi_liointc->address, acpi_liointc->size,
|
||||
1, domain_handle, NULL);
|
||||
ret = liointc_init(addr, acpi_liointc->size, 1, domain_handle, NULL);
|
||||
if (ret == 0)
|
||||
ret = acpi_cascade_irqdomain_init();
|
||||
else
|
||||
|
||||
@@ -263,12 +263,13 @@ struct fwnode_handle *get_pch_msi_handle(int pci_segment)
|
||||
|
||||
int __init pch_msi_acpi_init(struct irq_domain *parent, struct acpi_madt_msi_pic *acpi_pchmsi)
|
||||
{
|
||||
int ret;
|
||||
phys_addr_t msg_address = (phys_addr_t)acpi_pchmsi->msg_address;
|
||||
struct fwnode_handle *domain_handle;
|
||||
int ret;
|
||||
|
||||
domain_handle = irq_domain_alloc_fwnode(&acpi_pchmsi->msg_address);
|
||||
ret = pch_msi_init(acpi_pchmsi->msg_address, acpi_pchmsi->start,
|
||||
acpi_pchmsi->count, parent, domain_handle);
|
||||
domain_handle = irq_domain_alloc_fwnode(&msg_address);
|
||||
ret = pch_msi_init(msg_address, acpi_pchmsi->start, acpi_pchmsi->count,
|
||||
parent, domain_handle);
|
||||
if (ret < 0)
|
||||
irq_domain_free_fwnode(domain_handle);
|
||||
|
||||
|
||||
@@ -343,7 +343,7 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
|
||||
priv->table[i] = PIC_UNDEF_VECTOR;
|
||||
|
||||
priv->ht_vec_base = vec_base;
|
||||
priv->vec_count = ((readq(priv->base) >> 48) & 0xff) + 1;
|
||||
priv->vec_count = ((readl(priv->base + 4) >> 16) & 0xff) + 1;
|
||||
priv->gsi_base = gsi_base;
|
||||
|
||||
priv->pic_domain = irq_domain_create_hierarchy(parent_domain, 0,
|
||||
@@ -446,23 +446,23 @@ static int __init acpi_cascade_irqdomain_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init pch_pic_acpi_init(struct irq_domain *parent,
|
||||
struct acpi_madt_bio_pic *acpi_pchpic)
|
||||
int __init pch_pic_acpi_init(struct irq_domain *parent, struct acpi_madt_bio_pic *acpi_pchpic)
|
||||
{
|
||||
int ret;
|
||||
phys_addr_t addr = (phys_addr_t)acpi_pchpic->address;
|
||||
struct fwnode_handle *domain_handle;
|
||||
int ret;
|
||||
|
||||
if (find_pch_pic(acpi_pchpic->gsi_base) >= 0)
|
||||
return 0;
|
||||
|
||||
domain_handle = irq_domain_alloc_fwnode(&acpi_pchpic->address);
|
||||
domain_handle = irq_domain_alloc_fwnode(&addr);
|
||||
if (!domain_handle) {
|
||||
pr_err("Unable to allocate domain handle\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = pch_pic_init(acpi_pchpic->address, acpi_pchpic->size,
|
||||
0, parent, domain_handle, acpi_pchpic->gsi_base);
|
||||
ret = pch_pic_init(addr, acpi_pchpic->size, 0, parent,
|
||||
domain_handle, acpi_pchpic->gsi_base);
|
||||
|
||||
if (ret < 0) {
|
||||
irq_domain_free_fwnode(domain_handle);
|
||||
|
||||
280
drivers/irqchip/irq-renesas-rzt2h.c
Normal file
280
drivers/irqchip/irq-renesas-rzt2h.c
Normal file
@@ -0,0 +1,280 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/irqchip/irq-renesas-rzt2h.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define RZT2H_ICU_INTCPU_NS_START 0
|
||||
#define RZT2H_ICU_INTCPU_NS_COUNT 14
|
||||
|
||||
#define RZT2H_ICU_INTCPU_S_START (RZT2H_ICU_INTCPU_NS_START + \
|
||||
RZT2H_ICU_INTCPU_NS_COUNT)
|
||||
#define RZT2H_ICU_INTCPU_S_COUNT 2
|
||||
|
||||
#define RZT2H_ICU_IRQ_NS_START (RZT2H_ICU_INTCPU_S_START + \
|
||||
RZT2H_ICU_INTCPU_S_COUNT)
|
||||
#define RZT2H_ICU_IRQ_NS_COUNT 14
|
||||
|
||||
#define RZT2H_ICU_IRQ_S_START (RZT2H_ICU_IRQ_NS_START + \
|
||||
RZT2H_ICU_IRQ_NS_COUNT)
|
||||
#define RZT2H_ICU_IRQ_S_COUNT 2
|
||||
|
||||
#define RZT2H_ICU_SEI_START (RZT2H_ICU_IRQ_S_START + \
|
||||
RZT2H_ICU_IRQ_S_COUNT)
|
||||
#define RZT2H_ICU_SEI_COUNT 1
|
||||
|
||||
#define RZT2H_ICU_NUM_IRQ (RZT2H_ICU_INTCPU_NS_COUNT + \
|
||||
RZT2H_ICU_INTCPU_S_COUNT + \
|
||||
RZT2H_ICU_IRQ_NS_COUNT + \
|
||||
RZT2H_ICU_IRQ_S_COUNT + \
|
||||
RZT2H_ICU_SEI_COUNT)
|
||||
|
||||
#define RZT2H_ICU_IRQ_IN_RANGE(n, type) \
|
||||
((n) >= RZT2H_ICU_##type##_START && \
|
||||
(n) < RZT2H_ICU_##type##_START + RZT2H_ICU_##type##_COUNT)
|
||||
|
||||
#define RZT2H_ICU_PORTNF_MD 0xc
|
||||
#define RZT2H_ICU_PORTNF_MDi_MASK(i) (GENMASK(1, 0) << ((i) * 2))
|
||||
#define RZT2H_ICU_PORTNF_MDi_PREP(i, val) (FIELD_PREP(GENMASK(1, 0), val) << ((i) * 2))
|
||||
|
||||
#define RZT2H_ICU_MD_LOW_LEVEL 0b00
|
||||
#define RZT2H_ICU_MD_FALLING_EDGE 0b01
|
||||
#define RZT2H_ICU_MD_RISING_EDGE 0b10
|
||||
#define RZT2H_ICU_MD_BOTH_EDGES 0b11
|
||||
|
||||
#define RZT2H_ICU_DMACn_RSSELi(n, i) (0x7d0 + 0x18 * (n) + 0x4 * (i))
|
||||
#define RZT2H_ICU_DMAC_REQ_SELx_MASK(x) (GENMASK(9, 0) << ((x) * 10))
|
||||
#define RZT2H_ICU_DMAC_REQ_SELx_PREP(x, val) (FIELD_PREP(GENMASK(9, 0), val) << ((x) * 10))
|
||||
|
||||
struct rzt2h_icu_priv {
|
||||
void __iomem *base_ns;
|
||||
void __iomem *base_s;
|
||||
struct irq_fwspec fwspec[RZT2H_ICU_NUM_IRQ];
|
||||
raw_spinlock_t lock;
|
||||
};
|
||||
|
||||
void rzt2h_icu_register_dma_req(struct platform_device *icu_dev, u8 dmac_index, u8 dmac_channel,
|
||||
u16 req_no)
|
||||
{
|
||||
struct rzt2h_icu_priv *priv = platform_get_drvdata(icu_dev);
|
||||
u8 y, upper;
|
||||
u32 val;
|
||||
|
||||
y = dmac_channel / 3;
|
||||
upper = dmac_channel % 3;
|
||||
|
||||
guard(raw_spinlock_irqsave)(&priv->lock);
|
||||
val = readl(priv->base_ns + RZT2H_ICU_DMACn_RSSELi(dmac_index, y));
|
||||
val &= ~RZT2H_ICU_DMAC_REQ_SELx_MASK(upper);
|
||||
val |= RZT2H_ICU_DMAC_REQ_SELx_PREP(upper, req_no);
|
||||
writel(val, priv->base_ns + RZT2H_ICU_DMACn_RSSELi(dmac_index, y));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rzt2h_icu_register_dma_req);
|
||||
|
||||
static inline struct rzt2h_icu_priv *irq_data_to_priv(struct irq_data *data)
|
||||
{
|
||||
return data->domain->host_data;
|
||||
}
|
||||
|
||||
static inline int rzt2h_icu_irq_to_offset(struct irq_data *d, void __iomem **base,
|
||||
unsigned int *offset)
|
||||
{
|
||||
struct rzt2h_icu_priv *priv = irq_data_to_priv(d);
|
||||
unsigned int hwirq = irqd_to_hwirq(d);
|
||||
|
||||
/*
|
||||
* Safety IRQs and SEI use a separate register space from the non-safety IRQs.
|
||||
* SEI interrupt number follows immediately after the safety IRQs.
|
||||
*/
|
||||
if (RZT2H_ICU_IRQ_IN_RANGE(hwirq, IRQ_NS)) {
|
||||
*offset = hwirq - RZT2H_ICU_IRQ_NS_START;
|
||||
*base = priv->base_ns;
|
||||
} else if (RZT2H_ICU_IRQ_IN_RANGE(hwirq, IRQ_S) || RZT2H_ICU_IRQ_IN_RANGE(hwirq, SEI)) {
|
||||
*offset = hwirq - RZT2H_ICU_IRQ_S_START;
|
||||
*base = priv->base_s;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rzt2h_icu_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct rzt2h_icu_priv *priv = irq_data_to_priv(d);
|
||||
unsigned int offset, parent_type;
|
||||
void __iomem *base;
|
||||
u32 val, md;
|
||||
int ret;
|
||||
|
||||
ret = rzt2h_icu_irq_to_offset(d, &base, &offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (type & IRQ_TYPE_SENSE_MASK) {
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
md = RZT2H_ICU_MD_LOW_LEVEL;
|
||||
parent_type = IRQ_TYPE_LEVEL_HIGH;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
md = RZT2H_ICU_MD_FALLING_EDGE;
|
||||
parent_type = IRQ_TYPE_EDGE_RISING;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
md = RZT2H_ICU_MD_RISING_EDGE;
|
||||
parent_type = IRQ_TYPE_EDGE_RISING;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
md = RZT2H_ICU_MD_BOTH_EDGES;
|
||||
parent_type = IRQ_TYPE_EDGE_RISING;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
scoped_guard(raw_spinlock, &priv->lock) {
|
||||
val = readl_relaxed(base + RZT2H_ICU_PORTNF_MD);
|
||||
val &= ~RZT2H_ICU_PORTNF_MDi_MASK(offset);
|
||||
val |= RZT2H_ICU_PORTNF_MDi_PREP(offset, md);
|
||||
writel_relaxed(val, base + RZT2H_ICU_PORTNF_MD);
|
||||
}
|
||||
|
||||
return irq_chip_set_type_parent(d, parent_type);
|
||||
}
|
||||
|
||||
static int rzt2h_icu_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
unsigned int hw_irq = irqd_to_hwirq(d);
|
||||
|
||||
/* IRQn and SEI are selectable, others are edge-only. */
|
||||
if (RZT2H_ICU_IRQ_IN_RANGE(hw_irq, IRQ_NS) ||
|
||||
RZT2H_ICU_IRQ_IN_RANGE(hw_irq, IRQ_S) ||
|
||||
RZT2H_ICU_IRQ_IN_RANGE(hw_irq, SEI))
|
||||
return rzt2h_icu_irq_set_type(d, type);
|
||||
|
||||
if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_EDGE_RISING)
|
||||
return -EINVAL;
|
||||
|
||||
return irq_chip_set_type_parent(d, IRQ_TYPE_EDGE_RISING);
|
||||
}
|
||||
|
||||
static const struct irq_chip rzt2h_icu_chip = {
|
||||
.name = "rzt2h-icu",
|
||||
.irq_mask = irq_chip_mask_parent,
|
||||
.irq_unmask = irq_chip_unmask_parent,
|
||||
.irq_eoi = irq_chip_eoi_parent,
|
||||
.irq_set_type = rzt2h_icu_set_type,
|
||||
.irq_set_wake = irq_chip_set_wake_parent,
|
||||
.irq_set_affinity = irq_chip_set_affinity_parent,
|
||||
.irq_retrigger = irq_chip_retrigger_hierarchy,
|
||||
.irq_get_irqchip_state = irq_chip_get_parent_state,
|
||||
.irq_set_irqchip_state = irq_chip_set_parent_state,
|
||||
.flags = IRQCHIP_MASK_ON_SUSPEND |
|
||||
IRQCHIP_SET_TYPE_MASKED |
|
||||
IRQCHIP_SKIP_SET_WAKE,
|
||||
};
|
||||
|
||||
static int rzt2h_icu_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs,
|
||||
void *arg)
|
||||
{
|
||||
struct rzt2h_icu_priv *priv = domain->host_data;
|
||||
irq_hw_number_t hwirq;
|
||||
unsigned int type;
|
||||
int ret;
|
||||
|
||||
ret = irq_domain_translate_twocell(domain, arg, &hwirq, &type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &rzt2h_icu_chip, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &priv->fwspec[hwirq]);
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops rzt2h_icu_domain_ops = {
|
||||
.alloc = rzt2h_icu_alloc,
|
||||
.free = irq_domain_free_irqs_common,
|
||||
.translate = irq_domain_translate_twocell,
|
||||
};
|
||||
|
||||
static int rzt2h_icu_parse_interrupts(struct rzt2h_icu_priv *priv, struct device_node *np)
|
||||
{
|
||||
struct of_phandle_args map;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < RZT2H_ICU_NUM_IRQ; i++) {
|
||||
ret = of_irq_parse_one(np, i, &map);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
of_phandle_args_to_fwspec(np, map.args, map.args_count, &priv->fwspec[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rzt2h_icu_init(struct platform_device *pdev, struct device_node *parent)
|
||||
{
|
||||
struct irq_domain *irq_domain, *parent_domain;
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rzt2h_icu_priv *priv;
|
||||
int ret;
|
||||
|
||||
parent_domain = irq_find_host(parent);
|
||||
if (!parent_domain)
|
||||
return dev_err_probe(dev, -ENODEV, "cannot find parent domain\n");
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
raw_spin_lock_init(&priv->lock);
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
priv->base_ns = devm_of_iomap(dev, dev->of_node, 0, NULL);
|
||||
if (IS_ERR(priv->base_ns))
|
||||
return PTR_ERR(priv->base_ns);
|
||||
|
||||
priv->base_s = devm_of_iomap(dev, dev->of_node, 1, NULL);
|
||||
if (IS_ERR(priv->base_s))
|
||||
return PTR_ERR(priv->base_s);
|
||||
|
||||
ret = rzt2h_icu_parse_interrupts(priv, node);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "cannot parse interrupts: %d\n", ret);
|
||||
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "devm_pm_runtime_enable failed: %d\n", ret);
|
||||
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "pm_runtime_resume_and_get failed: %d\n", ret);
|
||||
|
||||
irq_domain = irq_domain_create_hierarchy(parent_domain, 0, RZT2H_ICU_NUM_IRQ,
|
||||
dev_fwnode(dev), &rzt2h_icu_domain_ops, priv);
|
||||
if (!irq_domain) {
|
||||
pm_runtime_put(dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
IRQCHIP_PLATFORM_DRIVER_BEGIN(rzt2h_icu)
|
||||
IRQCHIP_MATCH("renesas,r9a09g077-icu", rzt2h_icu_init)
|
||||
IRQCHIP_PLATFORM_DRIVER_END(rzt2h_icu)
|
||||
MODULE_AUTHOR("Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>");
|
||||
MODULE_DESCRIPTION("Renesas RZ/T2H ICU Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
/* DT "interrupts" indexes */
|
||||
#define ICU_IRQ_START 1
|
||||
@@ -89,6 +90,18 @@
|
||||
#define ICU_RZG3E_TSSEL_MAX_VAL 0x8c
|
||||
#define ICU_RZV2H_TSSEL_MAX_VAL 0x55
|
||||
|
||||
/**
|
||||
* struct rzv2h_irqc_reg_cache - registers cache (necessary for suspend/resume)
|
||||
* @nitsr: ICU_NITSR register
|
||||
* @iitsr: ICU_IITSR register
|
||||
* @titsr: ICU_TITSR registers
|
||||
*/
|
||||
struct rzv2h_irqc_reg_cache {
|
||||
u32 nitsr;
|
||||
u32 iitsr;
|
||||
u32 titsr[2];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rzv2h_hw_info - Interrupt Control Unit controller hardware info structure.
|
||||
* @tssel_lut: TINT lookup table
|
||||
@@ -118,13 +131,15 @@ struct rzv2h_hw_info {
|
||||
* @fwspec: IRQ firmware specific data
|
||||
* @lock: Lock to serialize access to hardware registers
|
||||
* @info: Pointer to struct rzv2h_hw_info
|
||||
* @cache: Registers cache for suspend/resume
|
||||
*/
|
||||
struct rzv2h_icu_priv {
|
||||
static struct rzv2h_icu_priv {
|
||||
void __iomem *base;
|
||||
struct irq_fwspec fwspec[ICU_NUM_IRQ];
|
||||
raw_spinlock_t lock;
|
||||
const struct rzv2h_hw_info *info;
|
||||
};
|
||||
struct rzv2h_irqc_reg_cache cache;
|
||||
} *rzv2h_icu_data;
|
||||
|
||||
void rzv2h_icu_register_dma_req(struct platform_device *icu_dev, u8 dmac_index, u8 dmac_channel,
|
||||
u16 req_no)
|
||||
@@ -419,6 +434,44 @@ static int rzv2h_icu_set_type(struct irq_data *d, unsigned int type)
|
||||
return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
|
||||
}
|
||||
|
||||
static int rzv2h_irqc_irq_suspend(void *data)
|
||||
{
|
||||
struct rzv2h_irqc_reg_cache *cache = &rzv2h_icu_data->cache;
|
||||
void __iomem *base = rzv2h_icu_data->base;
|
||||
|
||||
cache->nitsr = readl_relaxed(base + ICU_NITSR);
|
||||
cache->iitsr = readl_relaxed(base + ICU_IITSR);
|
||||
for (unsigned int i = 0; i < 2; i++)
|
||||
cache->titsr[i] = readl_relaxed(base + rzv2h_icu_data->info->t_offs + ICU_TITSR(i));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rzv2h_irqc_irq_resume(void *data)
|
||||
{
|
||||
struct rzv2h_irqc_reg_cache *cache = &rzv2h_icu_data->cache;
|
||||
void __iomem *base = rzv2h_icu_data->base;
|
||||
|
||||
/*
|
||||
* Restore only interrupt type. TSSRx will be restored at the
|
||||
* request of pin controller to avoid spurious interrupts due
|
||||
* to invalid PIN states.
|
||||
*/
|
||||
for (unsigned int i = 0; i < 2; i++)
|
||||
writel_relaxed(cache->titsr[i], base + rzv2h_icu_data->info->t_offs + ICU_TITSR(i));
|
||||
writel_relaxed(cache->iitsr, base + ICU_IITSR);
|
||||
writel_relaxed(cache->nitsr, base + ICU_NITSR);
|
||||
}
|
||||
|
||||
static const struct syscore_ops rzv2h_irqc_syscore_ops = {
|
||||
.suspend = rzv2h_irqc_irq_suspend,
|
||||
.resume = rzv2h_irqc_irq_resume,
|
||||
};
|
||||
|
||||
static struct syscore rzv2h_irqc_syscore = {
|
||||
.ops = &rzv2h_irqc_syscore_ops,
|
||||
};
|
||||
|
||||
static const struct irq_chip rzv2h_icu_chip = {
|
||||
.name = "rzv2h-icu",
|
||||
.irq_eoi = rzv2h_icu_eoi,
|
||||
@@ -502,7 +555,6 @@ static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_no
|
||||
{
|
||||
struct irq_domain *irq_domain, *parent_domain;
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct rzv2h_icu_priv *rzv2h_icu_data;
|
||||
struct reset_control *resetn;
|
||||
int ret;
|
||||
|
||||
@@ -560,6 +612,8 @@ static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_no
|
||||
|
||||
rzv2h_icu_data->info = hw_info;
|
||||
|
||||
register_syscore(&rzv2h_irqc_syscore);
|
||||
|
||||
/*
|
||||
* coccicheck complains about a missing put_device call before returning, but it's a false
|
||||
* positive. We still need &pdev->dev after successfully returning from this function.
|
||||
@@ -623,6 +677,7 @@ static int rzv2h_icu_probe(struct platform_device *pdev, struct device_node *par
|
||||
|
||||
IRQCHIP_PLATFORM_DRIVER_BEGIN(rzv2h_icu)
|
||||
IRQCHIP_MATCH("renesas,r9a09g047-icu", rzg3e_icu_probe)
|
||||
IRQCHIP_MATCH("renesas,r9a09g056-icu", rzv2h_icu_probe)
|
||||
IRQCHIP_MATCH("renesas,r9a09g057-icu", rzv2h_icu_probe)
|
||||
IRQCHIP_PLATFORM_DRIVER_END(rzv2h_icu)
|
||||
MODULE_AUTHOR("Fabrizio Castro <fabrizio.castro.jz@renesas.com>");
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
@@ -171,6 +172,15 @@ static void aplic_idc_set_delivery(struct aplic_idc *idc, bool en)
|
||||
writel(de, idc->regs + APLIC_IDC_IDELIVERY);
|
||||
}
|
||||
|
||||
void aplic_direct_restore_states(struct aplic_priv *priv)
|
||||
{
|
||||
struct aplic_direct *direct = container_of(priv, struct aplic_direct, priv);
|
||||
int cpu;
|
||||
|
||||
for_each_cpu(cpu, &direct->lmask)
|
||||
aplic_idc_set_delivery(per_cpu_ptr(&aplic_idcs, cpu), true);
|
||||
}
|
||||
|
||||
static int aplic_direct_dying_cpu(unsigned int cpu)
|
||||
{
|
||||
if (aplic_direct_parent_irq)
|
||||
|
||||
@@ -12,10 +12,169 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
#include "irq-riscv-aplic-main.h"
|
||||
|
||||
static LIST_HEAD(aplics);
|
||||
|
||||
static void aplic_restore_states(struct aplic_priv *priv)
|
||||
{
|
||||
struct aplic_saved_regs *saved_regs = &priv->saved_hw_regs;
|
||||
struct aplic_src_ctrl *srcs;
|
||||
void __iomem *regs;
|
||||
u32 nr_irqs, i;
|
||||
|
||||
regs = priv->regs;
|
||||
writel(saved_regs->domaincfg, regs + APLIC_DOMAINCFG);
|
||||
#ifdef CONFIG_RISCV_M_MODE
|
||||
writel(saved_regs->msiaddr, regs + APLIC_xMSICFGADDR);
|
||||
writel(saved_regs->msiaddrh, regs + APLIC_xMSICFGADDRH);
|
||||
#endif
|
||||
/*
|
||||
* The sourcecfg[i] has to be restored prior to the target[i], interrupt-pending and
|
||||
* interrupt-enable bits. The AIA specification states that "Whenever interrupt source i is
|
||||
* inactive in an interrupt domain, the corresponding interrupt-pending and interrupt-enable
|
||||
* bits within the domain are read-only zeros, and register target[i] is also read-only
|
||||
* zero."
|
||||
*/
|
||||
nr_irqs = priv->nr_irqs;
|
||||
for (i = 0; i < nr_irqs; i++) {
|
||||
srcs = &priv->saved_hw_regs.srcs[i];
|
||||
writel(srcs->sourcecfg, regs + APLIC_SOURCECFG_BASE + i * sizeof(u32));
|
||||
writel(srcs->target, regs + APLIC_TARGET_BASE + i * sizeof(u32));
|
||||
}
|
||||
|
||||
for (i = 0; i <= nr_irqs; i += 32) {
|
||||
srcs = &priv->saved_hw_regs.srcs[i];
|
||||
writel(-1U, regs + APLIC_CLRIE_BASE + (i / 32) * sizeof(u32));
|
||||
writel(srcs->ie, regs + APLIC_SETIE_BASE + (i / 32) * sizeof(u32));
|
||||
|
||||
/* Re-trigger the interrupts if it forwards interrupts to target harts by MSIs */
|
||||
if (!priv->nr_idcs)
|
||||
writel(readl(regs + APLIC_CLRIP_BASE + (i / 32) * sizeof(u32)),
|
||||
regs + APLIC_SETIP_BASE + (i / 32) * sizeof(u32));
|
||||
}
|
||||
|
||||
if (priv->nr_idcs)
|
||||
aplic_direct_restore_states(priv);
|
||||
}
|
||||
|
||||
static void aplic_save_states(struct aplic_priv *priv)
|
||||
{
|
||||
struct aplic_src_ctrl *srcs;
|
||||
void __iomem *regs;
|
||||
u32 i, nr_irqs;
|
||||
|
||||
regs = priv->regs;
|
||||
nr_irqs = priv->nr_irqs;
|
||||
/* The valid interrupt source IDs range from 1 to N, where N is priv->nr_irqs */
|
||||
for (i = 0; i < nr_irqs; i++) {
|
||||
srcs = &priv->saved_hw_regs.srcs[i];
|
||||
srcs->target = readl(regs + APLIC_TARGET_BASE + i * sizeof(u32));
|
||||
|
||||
if (i % 32)
|
||||
continue;
|
||||
|
||||
srcs->ie = readl(regs + APLIC_SETIE_BASE + (i / 32) * sizeof(u32));
|
||||
}
|
||||
|
||||
/* Save the nr_irqs bit if needed */
|
||||
if (!(nr_irqs % 32)) {
|
||||
srcs = &priv->saved_hw_regs.srcs[nr_irqs];
|
||||
srcs->ie = readl(regs + APLIC_SETIE_BASE + (nr_irqs / 32) * sizeof(u32));
|
||||
}
|
||||
}
|
||||
|
||||
static int aplic_syscore_suspend(void *data)
|
||||
{
|
||||
struct aplic_priv *priv;
|
||||
|
||||
list_for_each_entry(priv, &aplics, head)
|
||||
aplic_save_states(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aplic_syscore_resume(void *data)
|
||||
{
|
||||
struct aplic_priv *priv;
|
||||
|
||||
list_for_each_entry(priv, &aplics, head)
|
||||
aplic_restore_states(priv);
|
||||
}
|
||||
|
||||
static struct syscore_ops aplic_syscore_ops = {
|
||||
.suspend = aplic_syscore_suspend,
|
||||
.resume = aplic_syscore_resume,
|
||||
};
|
||||
|
||||
static struct syscore aplic_syscore = {
|
||||
.ops = &aplic_syscore_ops,
|
||||
};
|
||||
|
||||
static int aplic_pm_notifier(struct notifier_block *nb, unsigned long action, void *data)
|
||||
{
|
||||
struct aplic_priv *priv = container_of(nb, struct aplic_priv, genpd_nb);
|
||||
|
||||
switch (action) {
|
||||
case GENPD_NOTIFY_PRE_OFF:
|
||||
aplic_save_states(priv);
|
||||
break;
|
||||
case GENPD_NOTIFY_ON:
|
||||
aplic_restore_states(priv);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aplic_pm_remove(void *data)
|
||||
{
|
||||
struct aplic_priv *priv = data;
|
||||
struct device *dev = priv->dev;
|
||||
|
||||
list_del(&priv->head);
|
||||
if (dev->pm_domain)
|
||||
dev_pm_genpd_remove_notifier(dev);
|
||||
}
|
||||
|
||||
static int aplic_pm_add(struct device *dev, struct aplic_priv *priv)
|
||||
{
|
||||
struct aplic_src_ctrl *srcs;
|
||||
int ret;
|
||||
|
||||
srcs = devm_kzalloc(dev, (priv->nr_irqs + 1) * sizeof(*srcs), GFP_KERNEL);
|
||||
if (!srcs)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->saved_hw_regs.srcs = srcs;
|
||||
list_add(&priv->head, &aplics);
|
||||
if (dev->pm_domain) {
|
||||
priv->genpd_nb.notifier_call = aplic_pm_notifier;
|
||||
ret = dev_pm_genpd_add_notifier(dev, &priv->genpd_nb);
|
||||
if (ret)
|
||||
goto remove_head;
|
||||
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
goto remove_notifier;
|
||||
}
|
||||
|
||||
return devm_add_action_or_reset(dev, aplic_pm_remove, priv);
|
||||
|
||||
remove_notifier:
|
||||
dev_pm_genpd_remove_notifier(dev);
|
||||
remove_head:
|
||||
list_del(&priv->head);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void aplic_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct aplic_priv *priv = irq_data_get_irq_chip_data(d);
|
||||
@@ -60,6 +219,8 @@ int aplic_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
sourcecfg += (d->hwirq - 1) * sizeof(u32);
|
||||
writel(val, sourcecfg);
|
||||
|
||||
priv->saved_hw_regs.srcs[d->hwirq - 1].sourcecfg = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -82,6 +243,7 @@ int aplic_irqdomain_translate(struct irq_fwspec *fwspec, u32 gsi_base,
|
||||
|
||||
void aplic_init_hw_global(struct aplic_priv *priv, bool msi_mode)
|
||||
{
|
||||
struct aplic_saved_regs *saved_regs = &priv->saved_hw_regs;
|
||||
u32 val;
|
||||
#ifdef CONFIG_RISCV_M_MODE
|
||||
u32 valh;
|
||||
@@ -95,6 +257,8 @@ void aplic_init_hw_global(struct aplic_priv *priv, bool msi_mode)
|
||||
valh |= FIELD_PREP(APLIC_xMSICFGADDRH_HHXS, priv->msicfg.hhxs);
|
||||
writel(val, priv->regs + APLIC_xMSICFGADDR);
|
||||
writel(valh, priv->regs + APLIC_xMSICFGADDRH);
|
||||
saved_regs->msiaddr = val;
|
||||
saved_regs->msiaddrh = valh;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -106,6 +270,8 @@ void aplic_init_hw_global(struct aplic_priv *priv, bool msi_mode)
|
||||
writel(val, priv->regs + APLIC_DOMAINCFG);
|
||||
if (readl(priv->regs + APLIC_DOMAINCFG) != val)
|
||||
dev_warn(priv->dev, "unable to write 0x%x in domaincfg\n", val);
|
||||
|
||||
saved_regs->domaincfg = val;
|
||||
}
|
||||
|
||||
static void aplic_init_hw_irqs(struct aplic_priv *priv)
|
||||
@@ -176,7 +342,7 @@ int aplic_setup_priv(struct aplic_priv *priv, struct device *dev, void __iomem *
|
||||
/* Setup initial state APLIC interrupts */
|
||||
aplic_init_hw_irqs(priv);
|
||||
|
||||
return 0;
|
||||
return aplic_pm_add(dev, priv);
|
||||
}
|
||||
|
||||
static int aplic_probe(struct platform_device *pdev)
|
||||
@@ -209,6 +375,8 @@ static int aplic_probe(struct platform_device *pdev)
|
||||
if (rc)
|
||||
dev_err_probe(dev, rc, "failed to setup APLIC in %s mode\n",
|
||||
msi_mode ? "MSI" : "direct");
|
||||
else
|
||||
register_syscore(&aplic_syscore);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
if (!acpi_disabled)
|
||||
|
||||
@@ -23,7 +23,25 @@ struct aplic_msicfg {
|
||||
u32 lhxw;
|
||||
};
|
||||
|
||||
struct aplic_src_ctrl {
|
||||
u32 sourcecfg;
|
||||
u32 target;
|
||||
u32 ie;
|
||||
};
|
||||
|
||||
struct aplic_saved_regs {
|
||||
u32 domaincfg;
|
||||
#ifdef CONFIG_RISCV_M_MODE
|
||||
u32 msiaddr;
|
||||
u32 msiaddrh;
|
||||
#endif
|
||||
struct aplic_src_ctrl *srcs;
|
||||
};
|
||||
|
||||
struct aplic_priv {
|
||||
struct list_head head;
|
||||
struct notifier_block genpd_nb;
|
||||
struct aplic_saved_regs saved_hw_regs;
|
||||
struct device *dev;
|
||||
u32 gsi_base;
|
||||
u32 nr_irqs;
|
||||
@@ -40,6 +58,7 @@ int aplic_irqdomain_translate(struct irq_fwspec *fwspec, u32 gsi_base,
|
||||
unsigned long *hwirq, unsigned int *type);
|
||||
void aplic_init_hw_global(struct aplic_priv *priv, bool msi_mode);
|
||||
int aplic_setup_priv(struct aplic_priv *priv, struct device *dev, void __iomem *regs);
|
||||
void aplic_direct_restore_states(struct aplic_priv *priv);
|
||||
int aplic_direct_setup(struct device *dev, void __iomem *regs);
|
||||
#ifdef CONFIG_RISCV_APLIC_MSI
|
||||
int aplic_msi_setup(struct device *dev, void __iomem *regs);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define pr_fmt(fmt) "riscv-imsic: " fmt
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpu_pm.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
@@ -123,14 +124,8 @@ static void imsic_handle_irq(struct irq_desc *desc)
|
||||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
static int imsic_starting_cpu(unsigned int cpu)
|
||||
static void imsic_hw_states_init(void)
|
||||
{
|
||||
/* Mark per-CPU IMSIC state as online */
|
||||
imsic_state_online();
|
||||
|
||||
/* Enable per-CPU parent interrupt */
|
||||
enable_percpu_irq(imsic_parent_irq, irq_get_trigger_type(imsic_parent_irq));
|
||||
|
||||
/* Setup IPIs */
|
||||
imsic_ipi_starting_cpu();
|
||||
|
||||
@@ -142,6 +137,18 @@ static int imsic_starting_cpu(unsigned int cpu)
|
||||
|
||||
/* Enable local interrupt delivery */
|
||||
imsic_local_delivery(true);
|
||||
}
|
||||
|
||||
static int imsic_starting_cpu(unsigned int cpu)
|
||||
{
|
||||
/* Mark per-CPU IMSIC state as online */
|
||||
imsic_state_online();
|
||||
|
||||
/* Enable per-CPU parent interrupt */
|
||||
enable_percpu_irq(imsic_parent_irq, irq_get_trigger_type(imsic_parent_irq));
|
||||
|
||||
/* Initialize the IMSIC registers to enable the interrupt delivery */
|
||||
imsic_hw_states_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -157,6 +164,22 @@ static int imsic_dying_cpu(unsigned int cpu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imsic_pm_notifier(struct notifier_block *self, unsigned long cmd, void *v)
|
||||
{
|
||||
switch (cmd) {
|
||||
case CPU_PM_EXIT:
|
||||
/* Initialize the IMSIC registers to enable the interrupt delivery */
|
||||
imsic_hw_states_init();
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block imsic_pm_notifier_block = {
|
||||
.notifier_call = imsic_pm_notifier,
|
||||
};
|
||||
|
||||
static int __init imsic_early_probe(struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct irq_domain *domain;
|
||||
@@ -194,7 +217,7 @@ static int __init imsic_early_probe(struct fwnode_handle *fwnode)
|
||||
cpuhp_setup_state(CPUHP_AP_IRQ_RISCV_IMSIC_STARTING, "irqchip/riscv/imsic:starting",
|
||||
imsic_starting_cpu, imsic_dying_cpu);
|
||||
|
||||
return 0;
|
||||
return cpu_pm_register_notifier(&imsic_pm_notifier_block);
|
||||
}
|
||||
|
||||
static int __init imsic_early_dt_init(struct device_node *node, struct device_node *parent)
|
||||
|
||||
@@ -68,15 +68,17 @@
|
||||
#define PLIC_QUIRK_CP100_CLAIM_REGISTER_ERRATUM 1
|
||||
|
||||
struct plic_priv {
|
||||
struct fwnode_handle *fwnode;
|
||||
struct cpumask lmask;
|
||||
struct irq_domain *irqdomain;
|
||||
void __iomem *regs;
|
||||
unsigned long plic_quirks;
|
||||
unsigned int nr_irqs;
|
||||
unsigned long *prio_save;
|
||||
u32 gsi_base;
|
||||
int acpi_plic_id;
|
||||
struct fwnode_handle *fwnode;
|
||||
struct cpumask lmask;
|
||||
struct irq_domain *irqdomain;
|
||||
void __iomem *regs;
|
||||
unsigned long plic_quirks;
|
||||
/* device interrupts + 1 to compensate for the reserved hwirq 0 */
|
||||
unsigned int __private total_irqs;
|
||||
unsigned int irq_groups;
|
||||
unsigned long *prio_save;
|
||||
u32 gsi_base;
|
||||
int acpi_plic_id;
|
||||
};
|
||||
|
||||
struct plic_handler {
|
||||
@@ -91,6 +93,12 @@ struct plic_handler {
|
||||
u32 *enable_save;
|
||||
struct plic_priv *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* Macro to deal with the insanity of hardware interrupt 0 being reserved */
|
||||
#define for_each_device_irq(iter, priv) \
|
||||
for (unsigned int iter = 1; iter < ACCESS_PRIVATE(priv, total_irqs); iter++)
|
||||
|
||||
static int plic_parent_irq __ro_after_init;
|
||||
static bool plic_global_setup_done __ro_after_init;
|
||||
static DEFINE_PER_CPU(struct plic_handler, plic_handlers);
|
||||
@@ -257,14 +265,11 @@ static int plic_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
|
||||
static int plic_irq_suspend(void *data)
|
||||
{
|
||||
struct plic_priv *priv;
|
||||
struct plic_priv *priv = this_cpu_ptr(&plic_handlers)->priv;
|
||||
|
||||
priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv;
|
||||
|
||||
/* irq ID 0 is reserved */
|
||||
for (unsigned int i = 1; i < priv->nr_irqs; i++) {
|
||||
__assign_bit(i, priv->prio_save,
|
||||
readl(priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID));
|
||||
for_each_device_irq(irq, priv) {
|
||||
__assign_bit(irq, priv->prio_save,
|
||||
readl(priv->regs + PRIORITY_BASE + irq * PRIORITY_PER_ID));
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -272,18 +277,15 @@ static int plic_irq_suspend(void *data)
|
||||
|
||||
static void plic_irq_resume(void *data)
|
||||
{
|
||||
unsigned int i, index, cpu;
|
||||
struct plic_priv *priv = this_cpu_ptr(&plic_handlers)->priv;
|
||||
unsigned int index, cpu;
|
||||
unsigned long flags;
|
||||
u32 __iomem *reg;
|
||||
struct plic_priv *priv;
|
||||
|
||||
priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv;
|
||||
|
||||
/* irq ID 0 is reserved */
|
||||
for (i = 1; i < priv->nr_irqs; i++) {
|
||||
index = BIT_WORD(i);
|
||||
writel((priv->prio_save[index] & BIT_MASK(i)) ? 1 : 0,
|
||||
priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID);
|
||||
for_each_device_irq(irq, priv) {
|
||||
index = BIT_WORD(irq);
|
||||
writel((priv->prio_save[index] & BIT_MASK(irq)) ? 1 : 0,
|
||||
priv->regs + PRIORITY_BASE + irq * PRIORITY_PER_ID);
|
||||
}
|
||||
|
||||
for_each_present_cpu(cpu) {
|
||||
@@ -293,7 +295,7 @@ static void plic_irq_resume(void *data)
|
||||
continue;
|
||||
|
||||
raw_spin_lock_irqsave(&handler->enable_lock, flags);
|
||||
for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) {
|
||||
for (unsigned int i = 0; i < priv->irq_groups; i++) {
|
||||
reg = handler->enable_base + i * sizeof(u32);
|
||||
writel(handler->enable_save[i], reg);
|
||||
}
|
||||
@@ -431,7 +433,7 @@ static u32 cp100_isolate_pending_irq(int nr_irq_groups, struct plic_handler *han
|
||||
|
||||
static irq_hw_number_t cp100_get_hwirq(struct plic_handler *handler, void __iomem *claim)
|
||||
{
|
||||
int nr_irq_groups = DIV_ROUND_UP(handler->priv->nr_irqs, 32);
|
||||
int nr_irq_groups = handler->priv->irq_groups;
|
||||
u32 __iomem *enable = handler->enable_base;
|
||||
irq_hw_number_t hwirq = 0;
|
||||
u32 iso_mask;
|
||||
@@ -614,7 +616,6 @@ static int plic_probe(struct fwnode_handle *fwnode)
|
||||
struct plic_handler *handler;
|
||||
u32 nr_irqs, parent_hwirq;
|
||||
struct plic_priv *priv;
|
||||
irq_hw_number_t hwirq;
|
||||
void __iomem *regs;
|
||||
int id, context_id;
|
||||
u32 gsi_base;
|
||||
@@ -647,7 +648,16 @@ static int plic_probe(struct fwnode_handle *fwnode)
|
||||
|
||||
priv->fwnode = fwnode;
|
||||
priv->plic_quirks = plic_quirks;
|
||||
priv->nr_irqs = nr_irqs;
|
||||
/*
|
||||
* The firmware provides the number of device interrupts. As
|
||||
* hardware interrupt 0 is reserved, the number of total interrupts
|
||||
* is nr_irqs + 1.
|
||||
*/
|
||||
nr_irqs++;
|
||||
ACCESS_PRIVATE(priv, total_irqs) = nr_irqs;
|
||||
/* Precalculate the number of register groups */
|
||||
priv->irq_groups = DIV_ROUND_UP(nr_irqs, 32);
|
||||
|
||||
priv->regs = regs;
|
||||
priv->gsi_base = gsi_base;
|
||||
priv->acpi_plic_id = id;
|
||||
@@ -686,7 +696,7 @@ static int plic_probe(struct fwnode_handle *fwnode)
|
||||
u32 __iomem *enable_base = priv->regs + CONTEXT_ENABLE_BASE +
|
||||
i * CONTEXT_ENABLE_SIZE;
|
||||
|
||||
for (int j = 0; j <= nr_irqs / 32; j++)
|
||||
for (int j = 0; j < priv->irq_groups; j++)
|
||||
writel(0, enable_base + j);
|
||||
}
|
||||
continue;
|
||||
@@ -718,23 +728,21 @@ static int plic_probe(struct fwnode_handle *fwnode)
|
||||
context_id * CONTEXT_ENABLE_SIZE;
|
||||
handler->priv = priv;
|
||||
|
||||
handler->enable_save = kcalloc(DIV_ROUND_UP(nr_irqs, 32),
|
||||
sizeof(*handler->enable_save), GFP_KERNEL);
|
||||
handler->enable_save = kcalloc(priv->irq_groups, sizeof(*handler->enable_save),
|
||||
GFP_KERNEL);
|
||||
if (!handler->enable_save) {
|
||||
error = -ENOMEM;
|
||||
goto fail_cleanup_contexts;
|
||||
}
|
||||
done:
|
||||
for (hwirq = 1; hwirq <= nr_irqs; hwirq++) {
|
||||
for_each_device_irq(hwirq, priv) {
|
||||
plic_toggle(handler, hwirq, 0);
|
||||
writel(1, priv->regs + PRIORITY_BASE +
|
||||
hwirq * PRIORITY_PER_ID);
|
||||
writel(1, priv->regs + PRIORITY_BASE + hwirq * PRIORITY_PER_ID);
|
||||
}
|
||||
nr_handlers++;
|
||||
}
|
||||
|
||||
priv->irqdomain = irq_domain_create_linear(fwnode, nr_irqs + 1,
|
||||
&plic_irqdomain_ops, priv);
|
||||
priv->irqdomain = irq_domain_create_linear(fwnode, nr_irqs, &plic_irqdomain_ops, priv);
|
||||
if (WARN_ON(!priv->irqdomain)) {
|
||||
error = -ENOMEM;
|
||||
goto fail_cleanup_contexts;
|
||||
|
||||
@@ -61,12 +61,21 @@ static int ti_sci_intr_irq_domain_translate(struct irq_domain *domain,
|
||||
{
|
||||
struct ti_sci_intr_irq_domain *intr = domain->host_data;
|
||||
|
||||
if (fwspec->param_count != 1)
|
||||
return -EINVAL;
|
||||
if (intr->type) {
|
||||
/* Global interrupt-type */
|
||||
if (fwspec->param_count != 1)
|
||||
return -EINVAL;
|
||||
|
||||
*hwirq = fwspec->param[0];
|
||||
*type = intr->type;
|
||||
*hwirq = fwspec->param[0];
|
||||
*type = intr->type;
|
||||
} else {
|
||||
/* Per-Line interrupt-type */
|
||||
if (fwspec->param_count != 2)
|
||||
return -EINVAL;
|
||||
|
||||
*hwirq = fwspec->param[0];
|
||||
*type = fwspec->param[1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -128,11 +137,12 @@ static void ti_sci_intr_irq_domain_free(struct irq_domain *domain,
|
||||
* @domain: Pointer to the interrupt router IRQ domain
|
||||
* @virq: Corresponding Linux virtual IRQ number
|
||||
* @hwirq: Corresponding hwirq for the IRQ within this IRQ domain
|
||||
* @hwirq_type: Corresponding hwirq trigger type for the IRQ within this IRQ domain
|
||||
*
|
||||
* Returns intr output irq if all went well else appropriate error pointer.
|
||||
*/
|
||||
static int ti_sci_intr_alloc_parent_irq(struct irq_domain *domain,
|
||||
unsigned int virq, u32 hwirq)
|
||||
static int ti_sci_intr_alloc_parent_irq(struct irq_domain *domain, unsigned int virq,
|
||||
u32 hwirq, u32 hwirq_type)
|
||||
{
|
||||
struct ti_sci_intr_irq_domain *intr = domain->host_data;
|
||||
struct device_node *parent_node;
|
||||
@@ -156,11 +166,22 @@ static int ti_sci_intr_alloc_parent_irq(struct irq_domain *domain,
|
||||
fwspec.param_count = 3;
|
||||
fwspec.param[0] = 0; /* SPI */
|
||||
fwspec.param[1] = p_hwirq - 32; /* SPI offset */
|
||||
fwspec.param[2] = intr->type;
|
||||
fwspec.param[2] = hwirq_type;
|
||||
} else {
|
||||
/* Parent is Interrupt Router */
|
||||
fwspec.param_count = 1;
|
||||
fwspec.param[0] = p_hwirq;
|
||||
u32 parent_trigger_type;
|
||||
|
||||
if (!of_property_read_u32(parent_node, "ti,intr-trigger-type",
|
||||
&parent_trigger_type)) {
|
||||
/* Parent has global trigger type */
|
||||
fwspec.param_count = 1;
|
||||
fwspec.param[0] = p_hwirq;
|
||||
} else {
|
||||
/* Parent supports per-line trigger types */
|
||||
fwspec.param_count = 2;
|
||||
fwspec.param[0] = p_hwirq;
|
||||
fwspec.param[1] = hwirq_type;
|
||||
}
|
||||
}
|
||||
|
||||
err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
|
||||
@@ -196,15 +217,15 @@ static int ti_sci_intr_irq_domain_alloc(struct irq_domain *domain,
|
||||
void *data)
|
||||
{
|
||||
struct irq_fwspec *fwspec = data;
|
||||
unsigned int hwirq_type;
|
||||
unsigned long hwirq;
|
||||
unsigned int flags;
|
||||
int err, out_irq;
|
||||
|
||||
err = ti_sci_intr_irq_domain_translate(domain, fwspec, &hwirq, &flags);
|
||||
err = ti_sci_intr_irq_domain_translate(domain, fwspec, &hwirq, &hwirq_type);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
out_irq = ti_sci_intr_alloc_parent_irq(domain, virq, hwirq);
|
||||
out_irq = ti_sci_intr_alloc_parent_irq(domain, virq, hwirq, hwirq_type);
|
||||
if (out_irq < 0)
|
||||
return out_irq;
|
||||
|
||||
@@ -247,12 +268,9 @@ static int ti_sci_intr_irq_domain_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
intr->dev = dev;
|
||||
ret = of_property_read_u32(dev_of_node(dev), "ti,intr-trigger-type",
|
||||
&intr->type);
|
||||
if (ret) {
|
||||
dev_err(dev, "missing ti,intr-trigger-type property\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(dev_of_node(dev), "ti,intr-trigger-type", &intr->type))
|
||||
intr->type = IRQ_TYPE_NONE;
|
||||
|
||||
intr->sci = devm_ti_sci_get_by_phandle(dev, "ti,sci");
|
||||
if (IS_ERR(intr->sci))
|
||||
|
||||
@@ -423,6 +423,7 @@ config ARCH_R9A09G057
|
||||
config ARCH_R9A09G077
|
||||
bool "ARM64 Platform support for R9A09G077 (RZ/T2H)"
|
||||
default y if ARCH_RENESAS
|
||||
select RENESAS_RZT2H_ICU
|
||||
help
|
||||
This enables support for the Renesas RZ/T2H SoC variants.
|
||||
|
||||
|
||||
23
include/linux/irqchip/irq-renesas-rzt2h.h
Normal file
23
include/linux/irqchip/irq-renesas-rzt2h.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Renesas RZ/T2H Interrupt Control Unit (ICU)
|
||||
*
|
||||
* Copyright (C) 2025 Renesas Electronics Corporation.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_IRQ_RENESAS_RZT2H
|
||||
#define __LINUX_IRQ_RENESAS_RZT2H
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define RZT2H_ICU_DMAC_REQ_NO_DEFAULT 0x3ff
|
||||
|
||||
#ifdef CONFIG_RENESAS_RZT2H_ICU
|
||||
void rzt2h_icu_register_dma_req(struct platform_device *icu_dev, u8 dmac_index, u8 dmac_channel,
|
||||
u16 req_no);
|
||||
#else
|
||||
static inline void rzt2h_icu_register_dma_req(struct platform_device *icu_dev, u8 dmac_index,
|
||||
u8 dmac_channel, u16 req_no) { }
|
||||
#endif
|
||||
|
||||
#endif /* __LINUX_IRQ_RENESAS_RZT2H */
|
||||
Reference in New Issue
Block a user