* [PATCH 01/12] soc: fsl: qe: Add chained_irq_{enter,exit}() calls in cascade handler
2026-07-03 13:30 [PATCH 00/12] soc: fsl: qe: QE PIC improvement and add support of IRQs to QUICC ENGINE GPIOs Paul Louvel
@ 2026-07-03 13:30 ` Paul Louvel
2026-07-03 13:30 ` [PATCH 02/12] dt-bindings: soc: fsl: qe: Set #interrupt-cells to 2 to support interrupt type encoding Paul Louvel
` (10 subsequent siblings)
11 siblings, 0 replies; 19+ messages in thread
From: Paul Louvel @ 2026-07-03 13:30 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Thomas Petazzoni, stable
Wrap the cascade handler body with chained_irq_{enter,exit}() to
properly inform the parent IRQ chip that a chained interrupt is being
serviced.
Fixes: f0bcd784e1b76 ("soc: fsl: qe: Add an interrupt controller for QUICC Engine Ports")
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
Cc: stable@kernel.org
---
drivers/soc/fsl/qe/qe_ports_ic.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c
index 9b0bba64e91e..73a77763210d 100644
--- a/drivers/soc/fsl/qe/qe_ports_ic.c
+++ b/drivers/soc/fsl/qe/qe_ports_ic.c
@@ -6,6 +6,7 @@
*/
#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
#include <linux/platform_device.h>
@@ -79,7 +80,13 @@ static int qepic_get_irq(struct irq_desc *desc)
static void qepic_cascade(struct irq_desc *desc)
{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+
+ chained_irq_enter(chip, desc);
+
generic_handle_irq(qepic_get_irq(desc));
+
+ chained_irq_exit(chip, desc);
}
static int qepic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw)
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH 02/12] dt-bindings: soc: fsl: qe: Set #interrupt-cells to 2 to support interrupt type encoding
2026-07-03 13:30 [PATCH 00/12] soc: fsl: qe: QE PIC improvement and add support of IRQs to QUICC ENGINE GPIOs Paul Louvel
2026-07-03 13:30 ` [PATCH 01/12] soc: fsl: qe: Add chained_irq_{enter,exit}() calls in cascade handler Paul Louvel
@ 2026-07-03 13:30 ` Paul Louvel
2026-07-03 13:30 ` [PATCH 03/12] dt-bindings: soc: fsl: qe: Convert QE GPIO to DT schema Paul Louvel
` (9 subsequent siblings)
11 siblings, 0 replies; 19+ messages in thread
From: Paul Louvel @ 2026-07-03 13:30 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Thomas Petazzoni
The QUICC Engine port interrupt controller can be configured to generate
an interrupt on either a high-to-low transition or any change in the
signal state on the related GPIOs.
Update the #interrupt-cells property to 2 so consumers can encode
interrupt level information.
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
.../devicetree/bindings/interrupt-controller/fsl,qe-ports-ic.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,qe-ports-ic.yaml b/Documentation/devicetree/bindings/interrupt-controller/fsl,qe-ports-ic.yaml
index 2b8e7b9c6d7a..2b7c6b4f0389 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/fsl,qe-ports-ic.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,qe-ports-ic.yaml
@@ -23,7 +23,7 @@ properties:
const: 0
'#interrupt-cells':
- const: 1
+ const: 2
interrupts:
maxItems: 1
@@ -45,7 +45,7 @@ examples:
reg = <0xc00 0x18>;
interrupt-controller;
#address-cells = <0>;
- #interrupt-cells = <1>;
+ #interrupt-cells = <2>;
interrupts = <74 0x8>;
interrupt-parent = <&ipic>;
};
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH 03/12] dt-bindings: soc: fsl: qe: Convert QE GPIO to DT schema
2026-07-03 13:30 [PATCH 00/12] soc: fsl: qe: QE PIC improvement and add support of IRQs to QUICC ENGINE GPIOs Paul Louvel
2026-07-03 13:30 ` [PATCH 01/12] soc: fsl: qe: Add chained_irq_{enter,exit}() calls in cascade handler Paul Louvel
2026-07-03 13:30 ` [PATCH 02/12] dt-bindings: soc: fsl: qe: Set #interrupt-cells to 2 to support interrupt type encoding Paul Louvel
@ 2026-07-03 13:30 ` Paul Louvel
2026-07-06 6:48 ` Krzysztof Kozlowski
2026-07-03 13:30 ` [PATCH 04/12] dt-bindings: soc: fsl: qe: Add support of IRQ in QE GPIO Paul Louvel
` (8 subsequent siblings)
11 siblings, 1 reply; 19+ messages in thread
From: Paul Louvel @ 2026-07-03 13:30 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Thomas Petazzoni, Christophe Leroy
From: Christophe Leroy <christophe.leroy@csgroup.eu>
Convert QE GPIO devicetree binding to DT schema.
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
.../bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml | 45 ++++++++++++++++++++++
.../bindings/soc/fsl/cpm_qe/qe/par_io.txt | 26 +------------
2 files changed, 46 insertions(+), 25 deletions(-)
diff --git a/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
new file mode 100644
index 000000000000..1af99339ff40
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpio/fsl,mpc8323-qe-pario-bank.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale QUICC Engine Parallel I/O (QE PARIO) GPIO Bank
+
+maintainers:
+ - Christophe Leroy <christophe.leroy@csgroup.eu>
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - fsl,mpc8360-qe-pario-bank
+ - fsl,mpc8569-qe-pario-bank
+ - const: fsl,mpc8323-qe-pario-bank
+ - const: fsl,mpc8323-qe-pario-bank
+
+ reg:
+ maxItems: 1
+
+ gpio-controller: true
+
+ "#gpio-cells":
+ const: 2
+
+required:
+ - compatible
+ - reg
+ - gpio-controller
+ - "#gpio-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ gpio-controller@1400 {
+ compatible = "fsl,mpc8360-qe-pario-bank", "fsl,mpc8323-qe-pario-bank";
+ reg = <0x1400 0x18>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe/par_io.txt b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe/par_io.txt
index 09b1b05fa677..782699c14567 100644
--- a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe/par_io.txt
+++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe/par_io.txt
@@ -24,28 +24,4 @@ par_io@1400 {
Note that "par_io" nodes are obsolete, and should not be used for
the new device trees. Instead, each Par I/O bank should be represented
-via its own gpio-controller node:
-
-Required properties:
-- #gpio-cells : should be "2".
-- compatible : should be "fsl,<chip>-qe-pario-bank",
- "fsl,mpc8323-qe-pario-bank".
-- reg : offset to the register set and its length.
-- gpio-controller : node to identify gpio controllers.
-
-Example:
- qe_pio_a: gpio-controller@1400 {
- #gpio-cells = <2>;
- compatible = "fsl,mpc8360-qe-pario-bank",
- "fsl,mpc8323-qe-pario-bank";
- reg = <0x1400 0x18>;
- gpio-controller;
- };
-
- qe_pio_e: gpio-controller@1460 {
- #gpio-cells = <2>;
- compatible = "fsl,mpc8360-qe-pario-bank",
- "fsl,mpc8323-qe-pario-bank";
- reg = <0x1460 0x18>;
- gpio-controller;
- };
+via its own gpio-controller node.
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH 03/12] dt-bindings: soc: fsl: qe: Convert QE GPIO to DT schema
2026-07-03 13:30 ` [PATCH 03/12] dt-bindings: soc: fsl: qe: Convert QE GPIO to DT schema Paul Louvel
@ 2026-07-06 6:48 ` Krzysztof Kozlowski
2026-07-06 9:03 ` Paul Louvel
0 siblings, 1 reply; 19+ messages in thread
From: Krzysztof Kozlowski @ 2026-07-06 6:48 UTC (permalink / raw)
To: Paul Louvel
Cc: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, linuxppc-dev, linux-arm-kernel, linux-kernel,
devicetree, linux-gpio, Thomas Petazzoni
On Fri, Jul 03, 2026 at 03:30:11PM +0200, Paul Louvel wrote:
> diff --git a/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
> new file mode 100644
> index 000000000000..1af99339ff40
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
> @@ -0,0 +1,45 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/gpio/fsl,mpc8323-qe-pario-bank.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Freescale QUICC Engine Parallel I/O (QE PARIO) GPIO Bank
> +
> +maintainers:
> + - Christophe Leroy <christophe.leroy@csgroup.eu>
> +
> +properties:
> + compatible:
> + oneOf:
> + - items:
> + - enum:
> + - fsl,mpc8360-qe-pario-bank
> + - fsl,mpc8569-qe-pario-bank
None of these were in the old binding. You need to mention and
explain (WHY) the changes you are doing to the binding during the
conversion.
> + - const: fsl,mpc8323-qe-pario-bank
> + - const: fsl,mpc8323-qe-pario-bank
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 03/12] dt-bindings: soc: fsl: qe: Convert QE GPIO to DT schema
2026-07-06 6:48 ` Krzysztof Kozlowski
@ 2026-07-06 9:03 ` Paul Louvel
0 siblings, 0 replies; 19+ messages in thread
From: Paul Louvel @ 2026-07-06 9:03 UTC (permalink / raw)
To: Krzysztof Kozlowski, Paul Louvel
Cc: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, linuxppc-dev, linux-arm-kernel, linux-kernel,
devicetree, linux-gpio, Thomas Petazzoni
Hi Krzysztof,
On Mon Jul 6, 2026 at 8:48 AM CEST, Krzysztof Kozlowski wrote:
> On Fri, Jul 03, 2026 at 03:30:11PM +0200, Paul Louvel wrote:
>> diff --git a/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
>> new file mode 100644
>> index 000000000000..1af99339ff40
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
>> @@ -0,0 +1,45 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/gpio/fsl,mpc8323-qe-pario-bank.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Freescale QUICC Engine Parallel I/O (QE PARIO) GPIO Bank
>> +
>> +maintainers:
>> + - Christophe Leroy <christophe.leroy@csgroup.eu>
>> +
>> +properties:
>> + compatible:
>> + oneOf:
>> + - items:
>> + - enum:
>> + - fsl,mpc8360-qe-pario-bank
>> + - fsl,mpc8569-qe-pario-bank
>
> None of these were in the old binding. You need to mention and
> explain (WHY) the changes you are doing to the binding during the
> conversion.
Ok.
>
>> + - const: fsl,mpc8323-qe-pario-bank
>> + - const: fsl,mpc8323-qe-pario-bank
>
> Best regards,
> Krzysztof
Thanks,
Paul.
--
Paul Louvel, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 04/12] dt-bindings: soc: fsl: qe: Add support of IRQ in QE GPIO
2026-07-03 13:30 [PATCH 00/12] soc: fsl: qe: QE PIC improvement and add support of IRQs to QUICC ENGINE GPIOs Paul Louvel
` (2 preceding siblings ...)
2026-07-03 13:30 ` [PATCH 03/12] dt-bindings: soc: fsl: qe: Convert QE GPIO to DT schema Paul Louvel
@ 2026-07-03 13:30 ` Paul Louvel
2026-07-06 6:52 ` Krzysztof Kozlowski
2026-07-03 13:30 ` [PATCH 05/12] soc: fsl: qe: Use generic_handle_domain_irq() Paul Louvel
` (7 subsequent siblings)
11 siblings, 1 reply; 19+ messages in thread
From: Paul Louvel @ 2026-07-03 13:30 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Thomas Petazzoni
Some QE GPIO pins have an associated interrupt line in the QE PIC to
signal state changes on the pin. Add the corresponding
interrupt-controller / nexus properties to the QE GPIO binding.
Because the GPIO controller does not perform any interrupt handling
itself, a nexus node (interrupt-map) is used to map each GPIO line
supporting IRQ to the parent QE PIC interrupt domain.
As the QE PIC can be configured to generate an interrupt on either a
high-to-low transition or any change in signal state, three
interrupt-map entries are needed per GPIO pin that can yield an
interrupt (falling, both, and the "none" case which defaults to both in
QE PIC). This overhead is necessary because the interrupt-map-pass-thru
property is not part of the DT specification.
The interrupt-map property is optional: it is not required for GPIO
banks that have no interrupt capable GPIO line (e.g. port D on MPC8323),
or when interrupt functionality is not used.
Update the example to show a scenario where each bank supports a
different numbers of IRQs, or no IRQs at all.
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
.../bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml | 69 +++++++++++++++++++++-
1 file changed, 66 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
index 1af99339ff40..0c849a5698f4 100644
--- a/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
+++ b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
@@ -27,6 +27,17 @@ properties:
"#gpio-cells":
const: 2
+ "#address-cells":
+ const: 0
+
+ "#interrupt-cells":
+ const: 2
+
+ interrupt-map:
+ description: |
+ Specifies the mapping of GPIO lines to the parent interrupt controller, as the
+ GPIO controller does not do interrupt handling itself.
+
required:
- compatible
- reg
@@ -37,9 +48,61 @@ additionalProperties: false
examples:
- |
- gpio-controller@1400 {
- compatible = "fsl,mpc8360-qe-pario-bank", "fsl,mpc8323-qe-pario-bank";
- reg = <0x1400 0x18>;
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ pic: interrupt-controller {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ };
+
+ gpio-controller@1418 {
+ #gpio-cells = <2>;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ compatible = "fsl,mpc8323-qe-pario-bank";
+ reg = <0x1418 0x18>;
gpio-controller;
+ interrupt-map = <
+ 7 IRQ_TYPE_EDGE_FALLING &pic 4 IRQ_TYPE_EDGE_FALLING
+ 7 IRQ_TYPE_EDGE_BOTH &pic 4 IRQ_TYPE_EDGE_BOTH
+ 7 0 &pic 4 IRQ_TYPE_NONE
+
+ 9 IRQ_TYPE_EDGE_FALLING &pic 5 IRQ_TYPE_EDGE_FALLING
+ 9 IRQ_TYPE_EDGE_BOTH &pic 5 IRQ_TYPE_EDGE_BOTH
+ 9 0 &pic 5 IRQ_TYPE_NONE
+
+ 25 IRQ_TYPE_EDGE_FALLING &pic 6 IRQ_TYPE_EDGE_FALLING
+ 25 IRQ_TYPE_EDGE_BOTH &pic 6 IRQ_TYPE_EDGE_BOTH
+ 25 0 &pic 6 IRQ_TYPE_NONE
+
+ 27 IRQ_TYPE_EDGE_FALLING &pic 7 IRQ_TYPE_EDGE_FALLING
+ 27 IRQ_TYPE_EDGE_BOTH &pic 7 IRQ_TYPE_EDGE_BOTH
+ 27 0 &pic 7 IRQ_TYPE_NONE
+ >;
+ };
+
+ gpio-controller@1430 {
#gpio-cells = <2>;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ compatible = "fsl,mpc8323-qe-pario-bank";
+ reg = <0x1430 0x18>;
+ gpio-controller;
+ interrupt-map = <
+ 24 IRQ_TYPE_EDGE_FALLING &pic 8 IRQ_TYPE_EDGE_FALLING
+ 24 IRQ_TYPE_EDGE_BOTH &pic 8 IRQ_TYPE_EDGE_BOTH
+ 24 0 &pic 8 IRQ_TYPE_NONE
+
+ 29 IRQ_TYPE_EDGE_FALLING &pic 9 IRQ_TYPE_EDGE_FALLING
+ 29 IRQ_TYPE_EDGE_BOTH &pic 9 IRQ_TYPE_EDGE_BOTH
+ 29 0 &pic 9 IRQ_TYPE_NONE
+ >;
+ };
+
+ gpio-controller@1448 {
+ #gpio-cells = <2>;
+ compatible = "fsl,mpc8323-qe-pario-bank";
+ reg = <0x1448 0x18>;
+ gpio-controller;
};
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH 04/12] dt-bindings: soc: fsl: qe: Add support of IRQ in QE GPIO
2026-07-03 13:30 ` [PATCH 04/12] dt-bindings: soc: fsl: qe: Add support of IRQ in QE GPIO Paul Louvel
@ 2026-07-06 6:52 ` Krzysztof Kozlowski
2026-07-06 8:48 ` Paul Louvel
0 siblings, 1 reply; 19+ messages in thread
From: Krzysztof Kozlowski @ 2026-07-06 6:52 UTC (permalink / raw)
To: Paul Louvel
Cc: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, linuxppc-dev, linux-arm-kernel, linux-kernel,
devicetree, linux-gpio, Thomas Petazzoni
On Fri, Jul 03, 2026 at 03:30:12PM +0200, Paul Louvel wrote:
> Some QE GPIO pins have an associated interrupt line in the QE PIC to
> signal state changes on the pin. Add the corresponding
> interrupt-controller / nexus properties to the QE GPIO binding.
>
> Because the GPIO controller does not perform any interrupt handling
> itself, a nexus node (interrupt-map) is used to map each GPIO line
> supporting IRQ to the parent QE PIC interrupt domain.
>
> As the QE PIC can be configured to generate an interrupt on either a
> high-to-low transition or any change in signal state, three
> interrupt-map entries are needed per GPIO pin that can yield an
> interrupt (falling, both, and the "none" case which defaults to both in
> QE PIC). This overhead is necessary because the interrupt-map-pass-thru
> property is not part of the DT specification.
>
> The interrupt-map property is optional: it is not required for GPIO
> banks that have no interrupt capable GPIO line (e.g. port D on MPC8323),
> or when interrupt functionality is not used.
>
> Update the example to show a scenario where each bank supports a
> different numbers of IRQs, or no IRQs at all.
>
> Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
> ---
> .../bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml | 69 +++++++++++++++++++++-
> 1 file changed, 66 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
> index 1af99339ff40..0c849a5698f4 100644
> --- a/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
> +++ b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
> @@ -27,6 +27,17 @@ properties:
> "#gpio-cells":
> const: 2
>
> + "#address-cells":
> + const: 0
> +
> + "#interrupt-cells":
> + const: 2
> +
If this has interrupt-cells, then it is a nexus, thus why isn't this
also a "interrupt-controller"?
> + interrupt-map:
> + description: |
> + Specifies the mapping of GPIO lines to the parent interrupt controller, as the
> + GPIO controller does not do interrupt handling itself.
> +
> required:
> - compatible
> - reg
> @@ -37,9 +48,61 @@ additionalProperties: false
>
> examples:
> - |
> - gpio-controller@1400 {
> - compatible = "fsl,mpc8360-qe-pario-bank", "fsl,mpc8323-qe-pario-bank";
> - reg = <0x1400 0x18>;
I don't get why you rewrite existing example instead of adding new one.
> + #include <dt-bindings/interrupt-controller/irq.h>
> +
> + pic: interrupt-controller {
> + interrupt-controller;
> + #address-cells = <0>;
> + #interrupt-cells = <2>;
> + };
Drop node, irrelevant.
> +
> + gpio-controller@1418 {
> + #gpio-cells = <2>;
> + #address-cells = <0>;
> + #interrupt-cells = <2>;
> + compatible = "fsl,mpc8323-qe-pario-bank";
> + reg = <0x1418 0x18>;
And now you are not following DTS coding style.
> gpio-controller;
> + interrupt-map = <
> + 7 IRQ_TYPE_EDGE_FALLING &pic 4 IRQ_TYPE_EDGE_FALLING
> + 7 IRQ_TYPE_EDGE_BOTH &pic 4 IRQ_TYPE_EDGE_BOTH
> + 7 0 &pic 4 IRQ_TYPE_NONE
> +
> + 9 IRQ_TYPE_EDGE_FALLING &pic 5 IRQ_TYPE_EDGE_FALLING
> + 9 IRQ_TYPE_EDGE_BOTH &pic 5 IRQ_TYPE_EDGE_BOTH
> + 9 0 &pic 5 IRQ_TYPE_NONE
> +
> + 25 IRQ_TYPE_EDGE_FALLING &pic 6 IRQ_TYPE_EDGE_FALLING
> + 25 IRQ_TYPE_EDGE_BOTH &pic 6 IRQ_TYPE_EDGE_BOTH
> + 25 0 &pic 6 IRQ_TYPE_NONE
> +
> + 27 IRQ_TYPE_EDGE_FALLING &pic 7 IRQ_TYPE_EDGE_FALLING
> + 27 IRQ_TYPE_EDGE_BOTH &pic 7 IRQ_TYPE_EDGE_BOTH
> + 27 0 &pic 7 IRQ_TYPE_NONE
> + >;
> + };
> +
> + gpio-controller@1430 {
> #gpio-cells = <2>;
So two new examples? But old one was wrong?
> + #address-cells = <0>;
> + #interrupt-cells = <2>;
> + compatible = "fsl,mpc8323-qe-pario-bank";
> + reg = <0x1430 0x18>;
> + gpio-controller;
> + interrupt-map = <
> + 24 IRQ_TYPE_EDGE_FALLING &pic 8 IRQ_TYPE_EDGE_FALLING
> + 24 IRQ_TYPE_EDGE_BOTH &pic 8 IRQ_TYPE_EDGE_BOTH
> + 24 0 &pic 8 IRQ_TYPE_NONE
> +
> + 29 IRQ_TYPE_EDGE_FALLING &pic 9 IRQ_TYPE_EDGE_FALLING
> + 29 IRQ_TYPE_EDGE_BOTH &pic 9 IRQ_TYPE_EDGE_BOTH
> + 29 0 &pic 9 IRQ_TYPE_NONE
> + >;
> + };
> +
> + gpio-controller@1448 {
> + #gpio-cells = <2>;
> + compatible = "fsl,mpc8323-qe-pario-bank";
Wait, three examples? But isn't this the same as previous one?
> + reg = <0x1448 0x18>;
> + gpio-controller;
> };
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH 04/12] dt-bindings: soc: fsl: qe: Add support of IRQ in QE GPIO
2026-07-06 6:52 ` Krzysztof Kozlowski
@ 2026-07-06 8:48 ` Paul Louvel
0 siblings, 0 replies; 19+ messages in thread
From: Paul Louvel @ 2026-07-06 8:48 UTC (permalink / raw)
To: Krzysztof Kozlowski, Paul Louvel
Cc: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, linuxppc-dev, linux-arm-kernel, linux-kernel,
devicetree, linux-gpio, Thomas Petazzoni
On Mon Jul 6, 2026 at 8:52 AM CEST, Krzysztof Kozlowski wrote:
> On Fri, Jul 03, 2026 at 03:30:12PM +0200, Paul Louvel wrote:
>> Some QE GPIO pins have an associated interrupt line in the QE PIC to
>> signal state changes on the pin. Add the corresponding
>> interrupt-controller / nexus properties to the QE GPIO binding.
>>
>> Because the GPIO controller does not perform any interrupt handling
>> itself, a nexus node (interrupt-map) is used to map each GPIO line
>> supporting IRQ to the parent QE PIC interrupt domain.
>>
>> As the QE PIC can be configured to generate an interrupt on either a
>> high-to-low transition or any change in signal state, three
>> interrupt-map entries are needed per GPIO pin that can yield an
>> interrupt (falling, both, and the "none" case which defaults to both in
>> QE PIC). This overhead is necessary because the interrupt-map-pass-thru
>> property is not part of the DT specification.
>>
>> The interrupt-map property is optional: it is not required for GPIO
>> banks that have no interrupt capable GPIO line (e.g. port D on MPC8323),
>> or when interrupt functionality is not used.
>>
>> Update the example to show a scenario where each bank supports a
>> different numbers of IRQs, or no IRQs at all.
>>
>> Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
>> ---
>> .../bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml | 69 +++++++++++++++++++++-
>> 1 file changed, 66 insertions(+), 3 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
>> index 1af99339ff40..0c849a5698f4 100644
>> --- a/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
>> +++ b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml
>> @@ -27,6 +27,17 @@ properties:
>> "#gpio-cells":
>> const: 2
>>
>> + "#address-cells":
>> + const: 0
>> +
>> + "#interrupt-cells":
>> + const: 2
>> +
>
> If this has interrupt-cells, then it is a nexus, thus why isn't this
> also a "interrupt-controller"?
Because these these banks are not interrupt controllers.
Interrupts are handled by the QE PIC, and the GPIO controller does not do any
interrupt handling itself.
In this setup, does it really needs an "interrupt-controller" property?
>
>> + interrupt-map:
>> + description: |
>> + Specifies the mapping of GPIO lines to the parent interrupt controller, as the
>> + GPIO controller does not do interrupt handling itself.
>> +
>> required:
>> - compatible
>> - reg
>> @@ -37,9 +48,61 @@ additionalProperties: false
>>
>> examples:
>> - |
>> - gpio-controller@1400 {
>> - compatible = "fsl,mpc8360-qe-pario-bank", "fsl,mpc8323-qe-pario-bank";
>> - reg = <0x1400 0x18>;
>
> I don't get why you rewrite existing example instead of adding new one.
I could yes.
>
>> + #include <dt-bindings/interrupt-controller/irq.h>
>> +
>> + pic: interrupt-controller {
>> + interrupt-controller;
>> + #address-cells = <0>;
>> + #interrupt-cells = <2>;
>> + };
>
> Drop node, irrelevant.
>
>> +
>> + gpio-controller@1418 {
>> + #gpio-cells = <2>;
>> + #address-cells = <0>;
>> + #interrupt-cells = <2>;
>> + compatible = "fsl,mpc8323-qe-pario-bank";
>> + reg = <0x1418 0x18>;
>
> And now you are not following DTS coding style.
>
>> gpio-controller;
>> + interrupt-map = <
>> + 7 IRQ_TYPE_EDGE_FALLING &pic 4 IRQ_TYPE_EDGE_FALLING
>> + 7 IRQ_TYPE_EDGE_BOTH &pic 4 IRQ_TYPE_EDGE_BOTH
>> + 7 0 &pic 4 IRQ_TYPE_NONE
>> +
>> + 9 IRQ_TYPE_EDGE_FALLING &pic 5 IRQ_TYPE_EDGE_FALLING
>> + 9 IRQ_TYPE_EDGE_BOTH &pic 5 IRQ_TYPE_EDGE_BOTH
>> + 9 0 &pic 5 IRQ_TYPE_NONE
>> +
>> + 25 IRQ_TYPE_EDGE_FALLING &pic 6 IRQ_TYPE_EDGE_FALLING
>> + 25 IRQ_TYPE_EDGE_BOTH &pic 6 IRQ_TYPE_EDGE_BOTH
>> + 25 0 &pic 6 IRQ_TYPE_NONE
>> +
>> + 27 IRQ_TYPE_EDGE_FALLING &pic 7 IRQ_TYPE_EDGE_FALLING
>> + 27 IRQ_TYPE_EDGE_BOTH &pic 7 IRQ_TYPE_EDGE_BOTH
>> + 27 0 &pic 7 IRQ_TYPE_NONE
>> + >;
>> + };
>> +
>> + gpio-controller@1430 {
>> #gpio-cells = <2>;
>
> So two new examples? But old one was wrong?
>
>> + #address-cells = <0>;
>> + #interrupt-cells = <2>;
>> + compatible = "fsl,mpc8323-qe-pario-bank";
>> + reg = <0x1430 0x18>;
>> + gpio-controller;
>> + interrupt-map = <
>> + 24 IRQ_TYPE_EDGE_FALLING &pic 8 IRQ_TYPE_EDGE_FALLING
>> + 24 IRQ_TYPE_EDGE_BOTH &pic 8 IRQ_TYPE_EDGE_BOTH
>> + 24 0 &pic 8 IRQ_TYPE_NONE
>> +
>> + 29 IRQ_TYPE_EDGE_FALLING &pic 9 IRQ_TYPE_EDGE_FALLING
>> + 29 IRQ_TYPE_EDGE_BOTH &pic 9 IRQ_TYPE_EDGE_BOTH
>> + 29 0 &pic 9 IRQ_TYPE_NONE
>> + >;
>> + };
>> +
>> + gpio-controller@1448 {
>> + #gpio-cells = <2>;
>> + compatible = "fsl,mpc8323-qe-pario-bank";
>
> Wait, three examples? But isn't this the same as previous one?
I wanted to outline that each bank do not have the same number of GPIO lines
that support interrupts.
>
>> + reg = <0x1448 0x18>;
>> + gpio-controller;
>> };
>>
>> --
>> 2.55.0
>>
Thanks,
Paul.
--
Paul Louvel, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 05/12] soc: fsl: qe: Use generic_handle_domain_irq()
2026-07-03 13:30 [PATCH 00/12] soc: fsl: qe: QE PIC improvement and add support of IRQs to QUICC ENGINE GPIOs Paul Louvel
` (3 preceding siblings ...)
2026-07-03 13:30 ` [PATCH 04/12] dt-bindings: soc: fsl: qe: Add support of IRQ in QE GPIO Paul Louvel
@ 2026-07-03 13:30 ` Paul Louvel
2026-07-03 13:30 ` [PATCH 06/12] soc: fsl: qe: Iterate over all pending interrupts in cascade handler Paul Louvel
` (6 subsequent siblings)
11 siblings, 0 replies; 19+ messages in thread
From: Paul Louvel @ 2026-07-03 13:30 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Thomas Petazzoni
Replace the irq_find_mapping() + generic_handle_irq() pattern with
generic_handle_domain_irq(), which handles the IRQ domain lookup
internally. This is less error-prone and more idiomatic.
Remove the now-unused irq_find_mapping() call from qepic_get_irq().
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
drivers/soc/fsl/qe/qe_ports_ic.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c
index 73a77763210d..3bca116fd2f5 100644
--- a/drivers/soc/fsl/qe/qe_ports_ic.c
+++ b/drivers/soc/fsl/qe/qe_ports_ic.c
@@ -75,16 +75,17 @@ static int qepic_get_irq(struct irq_desc *desc)
if (!event)
return -1;
- return irq_find_mapping(data->host, 32 - ffs(event));
+ return 32 - ffs(event);
}
static void qepic_cascade(struct irq_desc *desc)
{
+ struct qepic_data *data = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
chained_irq_enter(chip, desc);
- generic_handle_irq(qepic_get_irq(desc));
+ generic_handle_domain_irq(data->host, qepic_get_irq(desc));
chained_irq_exit(chip, desc);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH 06/12] soc: fsl: qe: Iterate over all pending interrupts in cascade handler
2026-07-03 13:30 [PATCH 00/12] soc: fsl: qe: QE PIC improvement and add support of IRQs to QUICC ENGINE GPIOs Paul Louvel
` (4 preceding siblings ...)
2026-07-03 13:30 ` [PATCH 05/12] soc: fsl: qe: Use generic_handle_domain_irq() Paul Louvel
@ 2026-07-03 13:30 ` Paul Louvel
2026-07-03 13:30 ` [PATCH 07/12] soc: fsl: qe: Handle spurious interrupts Paul Louvel
` (5 subsequent siblings)
11 siblings, 0 replies; 19+ messages in thread
From: Paul Louvel @ 2026-07-03 13:30 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Thomas Petazzoni
Instead of only servicing a single interrupt, the chained handler can
handle all IRQs that have their bit set in the event register.
This avoid multiple parent IRQ handler being serviced if more than one
interrupt are pending on the QE PIC.
Remove unused code.
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
drivers/soc/fsl/qe/qe_ports_ic.c | 17 +++++------------
1 file changed, 5 insertions(+), 12 deletions(-)
diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c
index 3bca116fd2f5..27b62f4e3afb 100644
--- a/drivers/soc/fsl/qe/qe_ports_ic.c
+++ b/drivers/soc/fsl/qe/qe_ports_ic.c
@@ -5,6 +5,7 @@
* Copyright (c) 2025 Christophe Leroy CS GROUP France (christophe.leroy@csgroup.eu)
*/
+#include <linux/bitops.h>
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
@@ -67,25 +68,17 @@ static struct irq_chip qepic = {
.irq_set_type = qepic_set_type,
};
-static int qepic_get_irq(struct irq_desc *desc)
-{
- struct qepic_data *data = irq_desc_get_handler_data(desc);
- u32 event = in_be32(data->reg + CEPIER);
-
- if (!event)
- return -1;
-
- return 32 - ffs(event);
-}
-
static void qepic_cascade(struct irq_desc *desc)
{
struct qepic_data *data = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
+ unsigned long event, bit;
chained_irq_enter(chip, desc);
- generic_handle_domain_irq(data->host, qepic_get_irq(desc));
+ event = in_be32(data->reg + CEPIER);
+ for_each_set_bit(bit, &event, 32)
+ generic_handle_domain_irq(data->host, 32 - bit);
chained_irq_exit(chip, desc);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH 07/12] soc: fsl: qe: Handle spurious interrupts
2026-07-03 13:30 [PATCH 00/12] soc: fsl: qe: QE PIC improvement and add support of IRQs to QUICC ENGINE GPIOs Paul Louvel
` (5 preceding siblings ...)
2026-07-03 13:30 ` [PATCH 06/12] soc: fsl: qe: Iterate over all pending interrupts in cascade handler Paul Louvel
@ 2026-07-03 13:30 ` Paul Louvel
2026-07-03 13:30 ` [PATCH 08/12] soc: fsl: qe: Convert to generic IRQ chip Paul Louvel
` (4 subsequent siblings)
11 siblings, 0 replies; 19+ messages in thread
From: Paul Louvel @ 2026-07-03 13:30 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Thomas Petazzoni
When no interrupt bits are set in the event register, call
handle_bad_irq() to account for the spurious interrupt before
exiting the cascade handler.
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
drivers/soc/fsl/qe/qe_ports_ic.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c
index 27b62f4e3afb..c8b73b0aa233 100644
--- a/drivers/soc/fsl/qe/qe_ports_ic.c
+++ b/drivers/soc/fsl/qe/qe_ports_ic.c
@@ -77,9 +77,15 @@ static void qepic_cascade(struct irq_desc *desc)
chained_irq_enter(chip, desc);
event = in_be32(data->reg + CEPIER);
+ if (!event) {
+ handle_bad_irq(desc);
+ goto out;
+ }
+
for_each_set_bit(bit, &event, 32)
generic_handle_domain_irq(data->host, 32 - bit);
+out:
chained_irq_exit(chip, desc);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH 08/12] soc: fsl: qe: Convert to generic IRQ chip
2026-07-03 13:30 [PATCH 00/12] soc: fsl: qe: QE PIC improvement and add support of IRQs to QUICC ENGINE GPIOs Paul Louvel
` (6 preceding siblings ...)
2026-07-03 13:30 ` [PATCH 07/12] soc: fsl: qe: Handle spurious interrupts Paul Louvel
@ 2026-07-03 13:30 ` Paul Louvel
2026-07-06 7:29 ` Christophe Leroy (CS GROUP)
2026-07-03 13:30 ` [PATCH 09/12] soc: fsl: qe: Rename irq variable to parent_irq Paul Louvel
` (3 subsequent siblings)
11 siblings, 1 reply; 19+ messages in thread
From: Paul Louvel @ 2026-07-03 13:30 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Thomas Petazzoni
The generic IRQ chip framework is available to handle IRQ chips. Using
this framework for the QE interrupt controller allows to simplify the
driver. Indeed, the framework internally handles operations coded
directly in the driver.
Add a select dependency to GENERIC_IRQ_CHIP in the PPC platform Kconfig.
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
arch/powerpc/platforms/Kconfig | 1 +
drivers/soc/fsl/qe/qe_ports_ic.c | 103 ++++++++++++++++++++++++++-------------
2 files changed, 70 insertions(+), 34 deletions(-)
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index c4e61843d9d9..b0b3a80f8cde 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -232,6 +232,7 @@ config QE_GPIO
bool "QE GPIO support"
depends on QUICC_ENGINE
select GPIOLIB
+ select GENERIC_IRQ_CHIP
help
Say Y here if you're going to use hardware that connects to the
QE GPIOs.
diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c
index c8b73b0aa233..d022aa224f6d 100644
--- a/drivers/soc/fsl/qe/qe_ports_ic.c
+++ b/drivers/soc/fsl/qe/qe_ports_ic.c
@@ -20,63 +20,65 @@ struct qepic_data {
void __iomem *reg;
struct irq_domain *host;
int irq;
+ struct irq_chip_generic *gc;
};
static void qepic_mask(struct irq_data *d)
{
- struct qepic_data *data = irq_data_get_irq_chip_data(d);
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
- clrbits32(data->reg + CEPIMR, 1 << (31 - irqd_to_hwirq(d)));
+ clrbits32(gc->reg_base + ct->regs.mask, d->mask);
}
static void qepic_unmask(struct irq_data *d)
{
- struct qepic_data *data = irq_data_get_irq_chip_data(d);
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
- setbits32(data->reg + CEPIMR, 1 << (31 - irqd_to_hwirq(d)));
+ setbits32(gc->reg_base + ct->regs.mask, d->mask);
}
static void qepic_end(struct irq_data *d)
{
- struct qepic_data *data = irq_data_get_irq_chip_data(d);
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
- out_be32(data->reg + CEPIER, 1 << (31 - irqd_to_hwirq(d)));
+ out_be32(gc->reg_base + ct->regs.eoi, d->mask);
+}
+
+static void qepic_calc_mask(struct irq_data *d)
+{
+ d->mask = 1 << (31 - irqd_to_hwirq(d));
}
static int qepic_set_type(struct irq_data *d, unsigned int flow_type)
{
- struct qepic_data *data = irq_data_get_irq_chip_data(d);
- unsigned int vec = (unsigned int)irqd_to_hwirq(d);
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
switch (flow_type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_EDGE_FALLING:
- setbits32(data->reg + CEPICR, 1 << (31 - vec));
+ setbits32(gc->reg_base + ct->regs.type, d->mask);
return 0;
case IRQ_TYPE_EDGE_BOTH:
case IRQ_TYPE_NONE:
- clrbits32(data->reg + CEPICR, 1 << (31 - vec));
+ clrbits32(gc->reg_base + ct->regs.type, d->mask);
return 0;
}
return -EINVAL;
}
-static struct irq_chip qepic = {
- .name = "QEPIC",
- .irq_mask = qepic_mask,
- .irq_unmask = qepic_unmask,
- .irq_eoi = qepic_end,
- .irq_set_type = qepic_set_type,
-};
-
static void qepic_cascade(struct irq_desc *desc)
{
struct qepic_data *data = irq_desc_get_handler_data(desc);
+ struct irq_chip_type *ct = data->gc->chip_types;
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned long event, bit;
chained_irq_enter(chip, desc);
- event = in_be32(data->reg + CEPIER);
+ event = in_be32(data->gc->reg_base + ct->regs.eoi);
if (!event) {
handle_bad_irq(desc);
goto out;
@@ -89,33 +91,64 @@ static void qepic_cascade(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
-static int qepic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw)
+static int qepic_chip_init(struct irq_chip_generic *gc)
{
- irq_set_chip_data(virq, h->host_data);
- irq_set_chip_and_handler(virq, &qepic, handle_fasteoi_irq);
+ struct irq_chip_type *ct = gc->chip_types;
+
+ ct->regs.mask = CEPIMR;
+ ct->chip.irq_mask = qepic_mask;
+ ct->chip.irq_unmask = qepic_unmask;
+ ct->regs.eoi = CEPIER;
+ ct->chip.irq_eoi = qepic_end;
+ ct->regs.type = CEPICR;
+ ct->chip.irq_set_type = qepic_set_type;
+ ct->chip.irq_calc_mask = qepic_calc_mask;
+
return 0;
}
-static const struct irq_domain_ops qepic_host_ops = {
- .map = qepic_host_map,
-};
+static int qepic_domain_init(struct irq_domain *d)
+{
+ struct qepic_data *data = d->host_data;
-static void qepic_remove(void *res)
+ irq_set_chained_handler_and_data(data->irq, qepic_cascade, data);
+
+ return 0;
+}
+
+static void qepic_domain_exit(struct irq_domain *d)
{
- struct qepic_data *data = res;
+ struct qepic_data *data = d->host_data;
irq_set_chained_handler_and_data(data->irq, NULL, NULL);
- irq_domain_remove(data->host);
}
static int qepic_probe(struct platform_device *pdev)
{
+ struct irq_domain_chip_generic_info dgc_info = {
+ .name = "QEPIC",
+ .handler = handle_fasteoi_irq,
+ .irqs_per_chip = 32,
+ .num_ct = 1,
+ .init = qepic_chip_init,
+ };
+ struct irq_domain_info d_info = {
+ .fwnode = of_fwnode_handle(pdev->dev.of_node),
+ .domain_flags = IRQ_DOMAIN_FLAG_DESTROY_GC,
+ .size = 32,
+ .hwirq_max = 32,
+ .ops = &irq_generic_chip_ops,
+ .dgc_info = &dgc_info,
+ .init = qepic_domain_init,
+ .exit = qepic_domain_exit,
+ };
struct device *dev = &pdev->dev;
struct qepic_data *data;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
+ d_info.host_data = data;
data->reg = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(data->reg))
@@ -125,14 +158,16 @@ static int qepic_probe(struct platform_device *pdev)
if (data->irq < 0)
return data->irq;
- data->host = irq_domain_create_linear(dev_fwnode(dev), 32, &qepic_host_ops, data);
- if (!data->host)
- return -ENODEV;
+ data->host = devm_irq_domain_instantiate(dev, &d_info);
+ if (IS_ERR(data->host))
+ return PTR_ERR(data->host);
- irq_set_chained_handler_and_data(data->irq, qepic_cascade, data);
-
- return devm_add_action_or_reset(dev, qepic_remove, data);
+ data->gc = irq_get_domain_generic_chip(data->host, 0);
+ if (!data->gc)
+ return -ENODEV;
+ data->gc->reg_base = data->reg;
+ return 0;
}
static const struct of_device_id qepic_match[] = {
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* Re: [PATCH 08/12] soc: fsl: qe: Convert to generic IRQ chip
2026-07-03 13:30 ` [PATCH 08/12] soc: fsl: qe: Convert to generic IRQ chip Paul Louvel
@ 2026-07-06 7:29 ` Christophe Leroy (CS GROUP)
2026-07-06 8:56 ` Paul Louvel
0 siblings, 1 reply; 19+ messages in thread
From: Christophe Leroy (CS GROUP) @ 2026-07-06 7:29 UTC (permalink / raw)
To: Paul Louvel, Qiang Zhao, Thomas Gleixner, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Thomas Petazzoni
Hi Paul,
Le 03/07/2026 à 15:30, Paul Louvel a écrit :
> The generic IRQ chip framework is available to handle IRQ chips. Using
> this framework for the QE interrupt controller allows to simplify the
> driver. Indeed, the framework internally handles operations coded
> directly in the driver.
>
> Add a select dependency to GENERIC_IRQ_CHIP in the PPC platform Kconfig.
>
> Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
> ---
> arch/powerpc/platforms/Kconfig | 1 +
> drivers/soc/fsl/qe/qe_ports_ic.c | 103 ++++++++++++++++++++++++++-------------
> 2 files changed, 70 insertions(+), 34 deletions(-)
>
> diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
> index c4e61843d9d9..b0b3a80f8cde 100644
> --- a/arch/powerpc/platforms/Kconfig
> +++ b/arch/powerpc/platforms/Kconfig
> @@ -232,6 +232,7 @@ config QE_GPIO
> bool "QE GPIO support"
> depends on QUICC_ENGINE
> select GPIOLIB
> + select GENERIC_IRQ_CHIP
> help
> Say Y here if you're going to use hardware that connects to the
> QE GPIOs.
> diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c
> index c8b73b0aa233..d022aa224f6d 100644
> --- a/drivers/soc/fsl/qe/qe_ports_ic.c
> +++ b/drivers/soc/fsl/qe/qe_ports_ic.c
> @@ -20,63 +20,65 @@ struct qepic_data {
> void __iomem *reg;
> struct irq_domain *host;
> int irq;
> + struct irq_chip_generic *gc;
> };
>
> static void qepic_mask(struct irq_data *d)
> {
> - struct qepic_data *data = irq_data_get_irq_chip_data(d);
> + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
> + struct irq_chip_type *ct = irq_data_get_chip_type(d);
>
> - clrbits32(data->reg + CEPIMR, 1 << (31 - irqd_to_hwirq(d)));
> + clrbits32(gc->reg_base + ct->regs.mask, d->mask);
Is there a real added value with this change ?
Previously we had:
00000000 <qepic_mask>:
0: 81 03 00 18 lwz r8,24(r3)
4: 81 28 00 00 lwz r9,0(r8)
8: 7c 00 04 ac hwsync
c: 81 29 00 10 lwz r9,16(r9)
10: 0c 09 00 00 twi 0,r9,0
14: 4c 00 01 2c isync
18: 80 e3 00 08 lwz r7,8(r3)
1c: 3d 40 80 00 lis r10,-32768
20: 81 08 00 00 lwz r8,0(r8)
24: 7d 4a 3c 30 srw r10,r10,r7
28: 7d 29 50 78 andc r9,r9,r10
2c: 7c 00 04 ac hwsync
30: 91 28 00 10 stw r9,16(r8)
34: 4e 80 00 20 blr
Now we have:
00000000 <qepic_mask>:
0: 80 e3 00 18 lwz r7,24(r3)
4: 81 03 00 10 lwz r8,16(r3)
8: 81 27 00 00 lwz r9,0(r7)
c: 81 48 00 94 lwz r10,148(r8)
10: 7d 29 52 14 add r9,r9,r10
14: 7c 00 04 ac hwsync
18: 81 49 00 00 lwz r10,0(r9)
1c: 0c 0a 00 00 twi 0,r10,0
20: 4c 00 01 2c isync
24: 80 c3 00 00 lwz r6,0(r3)
28: 81 27 00 00 lwz r9,0(r7)
2c: 81 08 00 94 lwz r8,148(r8)
30: 7d 4a 30 78 andc r10,r10,r6
34: 7d 29 42 14 add r9,r9,r8
38: 7c 00 04 ac hwsync
3c: 91 49 00 00 stw r10,0(r9)
40: 4e 80 00 20 blr
We now have three more indirect loads (8x lwz instead of 5x), for
loading some value which is already known at compile time.
> }
>
> static void qepic_unmask(struct irq_data *d)
> {
> - struct qepic_data *data = irq_data_get_irq_chip_data(d);
> + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
> + struct irq_chip_type *ct = irq_data_get_chip_type(d);
>
> - setbits32(data->reg + CEPIMR, 1 << (31 - irqd_to_hwirq(d)));
> + setbits32(gc->reg_base + ct->regs.mask, d->mask);
> }
>
> static void qepic_end(struct irq_data *d)
> {
> - struct qepic_data *data = irq_data_get_irq_chip_data(d);
> + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
> + struct irq_chip_type *ct = irq_data_get_chip_type(d);
>
> - out_be32(data->reg + CEPIER, 1 << (31 - irqd_to_hwirq(d)));
> + out_be32(gc->reg_base + ct->regs.eoi, d->mask);
> +}
> +
> +static void qepic_calc_mask(struct irq_data *d)
> +{
> + d->mask = 1 << (31 - irqd_to_hwirq(d));
> }
>
> static int qepic_set_type(struct irq_data *d, unsigned int flow_type)
> {
> - struct qepic_data *data = irq_data_get_irq_chip_data(d);
> - unsigned int vec = (unsigned int)irqd_to_hwirq(d);
> + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
> + struct irq_chip_type *ct = irq_data_get_chip_type(d);
>
> switch (flow_type & IRQ_TYPE_SENSE_MASK) {
> case IRQ_TYPE_EDGE_FALLING:
> - setbits32(data->reg + CEPICR, 1 << (31 - vec));
> + setbits32(gc->reg_base + ct->regs.type, d->mask);
> return 0;
> case IRQ_TYPE_EDGE_BOTH:
> case IRQ_TYPE_NONE:
> - clrbits32(data->reg + CEPICR, 1 << (31 - vec));
> + clrbits32(gc->reg_base + ct->regs.type, d->mask);
> return 0;
> }
> return -EINVAL;
> }
>
> -static struct irq_chip qepic = {
> - .name = "QEPIC",
> - .irq_mask = qepic_mask,
> - .irq_unmask = qepic_unmask,
> - .irq_eoi = qepic_end,
> - .irq_set_type = qepic_set_type,
> -};
> -
> static void qepic_cascade(struct irq_desc *desc)
> {
> struct qepic_data *data = irq_desc_get_handler_data(desc);
> + struct irq_chip_type *ct = data->gc->chip_types;
> struct irq_chip *chip = irq_desc_get_chip(desc);
> unsigned long event, bit;
>
> chained_irq_enter(chip, desc);
>
> - event = in_be32(data->reg + CEPIER);
> + event = in_be32(data->gc->reg_base + ct->regs.eoi);
> if (!event) {
> handle_bad_irq(desc);
> goto out;
> @@ -89,33 +91,64 @@ static void qepic_cascade(struct irq_desc *desc)
> chained_irq_exit(chip, desc);
> }
>
> -static int qepic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw)
> +static int qepic_chip_init(struct irq_chip_generic *gc)
> {
> - irq_set_chip_data(virq, h->host_data);
> - irq_set_chip_and_handler(virq, &qepic, handle_fasteoi_irq);
> + struct irq_chip_type *ct = gc->chip_types;
> +
> + ct->regs.mask = CEPIMR;
> + ct->chip.irq_mask = qepic_mask;
> + ct->chip.irq_unmask = qepic_unmask;
> + ct->regs.eoi = CEPIER;
> + ct->chip.irq_eoi = qepic_end;
> + ct->regs.type = CEPICR;
> + ct->chip.irq_set_type = qepic_set_type;
> + ct->chip.irq_calc_mask = qepic_calc_mask;
Are ct->regs.mask, ct->regs.eoi and ct->regs.type used anywhere else
than locally in qepic_{mask/unmask/end/set_type} ?
Christophe
> +
> return 0;
> }
>
> -static const struct irq_domain_ops qepic_host_ops = {
> - .map = qepic_host_map,
> -};
> +static int qepic_domain_init(struct irq_domain *d)
> +{
> + struct qepic_data *data = d->host_data;
>
> -static void qepic_remove(void *res)
> + irq_set_chained_handler_and_data(data->irq, qepic_cascade, data);
> +
> + return 0;
> +}
> +
> +static void qepic_domain_exit(struct irq_domain *d)
> {
> - struct qepic_data *data = res;
> + struct qepic_data *data = d->host_data;
>
> irq_set_chained_handler_and_data(data->irq, NULL, NULL);
> - irq_domain_remove(data->host);
> }
>
> static int qepic_probe(struct platform_device *pdev)
> {
> + struct irq_domain_chip_generic_info dgc_info = {
> + .name = "QEPIC",
> + .handler = handle_fasteoi_irq,
> + .irqs_per_chip = 32,
> + .num_ct = 1,
> + .init = qepic_chip_init,
> + };
> + struct irq_domain_info d_info = {
> + .fwnode = of_fwnode_handle(pdev->dev.of_node),
> + .domain_flags = IRQ_DOMAIN_FLAG_DESTROY_GC,
> + .size = 32,
> + .hwirq_max = 32,
> + .ops = &irq_generic_chip_ops,
> + .dgc_info = &dgc_info,
> + .init = qepic_domain_init,
> + .exit = qepic_domain_exit,
> + };
> struct device *dev = &pdev->dev;
> struct qepic_data *data;
>
> data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> if (!data)
> return -ENOMEM;
> + d_info.host_data = data;
>
> data->reg = devm_platform_ioremap_resource(pdev, 0);
> if (IS_ERR(data->reg))
> @@ -125,14 +158,16 @@ static int qepic_probe(struct platform_device *pdev)
> if (data->irq < 0)
> return data->irq;
>
> - data->host = irq_domain_create_linear(dev_fwnode(dev), 32, &qepic_host_ops, data);
> - if (!data->host)
> - return -ENODEV;
> + data->host = devm_irq_domain_instantiate(dev, &d_info);
> + if (IS_ERR(data->host))
> + return PTR_ERR(data->host);
>
> - irq_set_chained_handler_and_data(data->irq, qepic_cascade, data);
> -
> - return devm_add_action_or_reset(dev, qepic_remove, data);
> + data->gc = irq_get_domain_generic_chip(data->host, 0);
> + if (!data->gc)
> + return -ENODEV;
> + data->gc->reg_base = data->reg;
>
> + return 0;
> }
>
> static const struct of_device_id qepic_match[] = {
>
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH 08/12] soc: fsl: qe: Convert to generic IRQ chip
2026-07-06 7:29 ` Christophe Leroy (CS GROUP)
@ 2026-07-06 8:56 ` Paul Louvel
0 siblings, 0 replies; 19+ messages in thread
From: Paul Louvel @ 2026-07-06 8:56 UTC (permalink / raw)
To: Christophe Leroy (CS GROUP), Paul Louvel, Qiang Zhao,
Thomas Gleixner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Linus Walleij, Bartosz Golaszewski, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Thomas Petazzoni
On Mon Jul 6, 2026 at 9:29 AM CEST, Christophe Leroy (CS GROUP) wrote:
> Hi Paul,
>
> Le 03/07/2026 à 15:30, Paul Louvel a écrit :
>> The generic IRQ chip framework is available to handle IRQ chips. Using
>> this framework for the QE interrupt controller allows to simplify the
>> driver. Indeed, the framework internally handles operations coded
>> directly in the driver.
>>
>> Add a select dependency to GENERIC_IRQ_CHIP in the PPC platform Kconfig.
>>
>> Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
>> ---
>> arch/powerpc/platforms/Kconfig | 1 +
>> drivers/soc/fsl/qe/qe_ports_ic.c | 103 ++++++++++++++++++++++++++-------------
>> 2 files changed, 70 insertions(+), 34 deletions(-)
>>
>> diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
>> index c4e61843d9d9..b0b3a80f8cde 100644
>> --- a/arch/powerpc/platforms/Kconfig
>> +++ b/arch/powerpc/platforms/Kconfig
>> @@ -232,6 +232,7 @@ config QE_GPIO
>> bool "QE GPIO support"
>> depends on QUICC_ENGINE
>> select GPIOLIB
>> + select GENERIC_IRQ_CHIP
>> help
>> Say Y here if you're going to use hardware that connects to the
>> QE GPIOs.
>> diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c
>> index c8b73b0aa233..d022aa224f6d 100644
>> --- a/drivers/soc/fsl/qe/qe_ports_ic.c
>> +++ b/drivers/soc/fsl/qe/qe_ports_ic.c
>> @@ -20,63 +20,65 @@ struct qepic_data {
>> void __iomem *reg;
>> struct irq_domain *host;
>> int irq;
>> + struct irq_chip_generic *gc;
>> };
>>
>> static void qepic_mask(struct irq_data *d)
>> {
>> - struct qepic_data *data = irq_data_get_irq_chip_data(d);
>> + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
>> + struct irq_chip_type *ct = irq_data_get_chip_type(d);
>>
>> - clrbits32(data->reg + CEPIMR, 1 << (31 - irqd_to_hwirq(d)));
>> + clrbits32(gc->reg_base + ct->regs.mask, d->mask);
>
> Is there a real added value with this change ?
>
> Previously we had:
>
> 00000000 <qepic_mask>:
> 0: 81 03 00 18 lwz r8,24(r3)
> 4: 81 28 00 00 lwz r9,0(r8)
> 8: 7c 00 04 ac hwsync
> c: 81 29 00 10 lwz r9,16(r9)
> 10: 0c 09 00 00 twi 0,r9,0
> 14: 4c 00 01 2c isync
> 18: 80 e3 00 08 lwz r7,8(r3)
> 1c: 3d 40 80 00 lis r10,-32768
> 20: 81 08 00 00 lwz r8,0(r8)
> 24: 7d 4a 3c 30 srw r10,r10,r7
> 28: 7d 29 50 78 andc r9,r9,r10
> 2c: 7c 00 04 ac hwsync
> 30: 91 28 00 10 stw r9,16(r8)
> 34: 4e 80 00 20 blr
>
> Now we have:
>
> 00000000 <qepic_mask>:
> 0: 80 e3 00 18 lwz r7,24(r3)
> 4: 81 03 00 10 lwz r8,16(r3)
> 8: 81 27 00 00 lwz r9,0(r7)
> c: 81 48 00 94 lwz r10,148(r8)
> 10: 7d 29 52 14 add r9,r9,r10
> 14: 7c 00 04 ac hwsync
> 18: 81 49 00 00 lwz r10,0(r9)
> 1c: 0c 0a 00 00 twi 0,r10,0
> 20: 4c 00 01 2c isync
> 24: 80 c3 00 00 lwz r6,0(r3)
> 28: 81 27 00 00 lwz r9,0(r7)
> 2c: 81 08 00 94 lwz r8,148(r8)
> 30: 7d 4a 30 78 andc r10,r10,r6
> 34: 7d 29 42 14 add r9,r9,r8
> 38: 7c 00 04 ac hwsync
> 3c: 91 49 00 00 stw r10,0(r9)
> 40: 4e 80 00 20 blr
>
> We now have three more indirect loads (8x lwz instead of 5x), for
> loading some value which is already known at compile time.
>
>
>> }
>>
>> static void qepic_unmask(struct irq_data *d)
>> {
>> - struct qepic_data *data = irq_data_get_irq_chip_data(d);
>> + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
>> + struct irq_chip_type *ct = irq_data_get_chip_type(d);
>>
>> - setbits32(data->reg + CEPIMR, 1 << (31 - irqd_to_hwirq(d)));
>> + setbits32(gc->reg_base + ct->regs.mask, d->mask);
>> }
>>
>> static void qepic_end(struct irq_data *d)
>> {
>> - struct qepic_data *data = irq_data_get_irq_chip_data(d);
>> + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
>> + struct irq_chip_type *ct = irq_data_get_chip_type(d);
>>
>> - out_be32(data->reg + CEPIER, 1 << (31 - irqd_to_hwirq(d)));
>> + out_be32(gc->reg_base + ct->regs.eoi, d->mask);
>> +}
>> +
>> +static void qepic_calc_mask(struct irq_data *d)
>> +{
>> + d->mask = 1 << (31 - irqd_to_hwirq(d));
>> }
>>
>> static int qepic_set_type(struct irq_data *d, unsigned int flow_type)
>> {
>> - struct qepic_data *data = irq_data_get_irq_chip_data(d);
>> - unsigned int vec = (unsigned int)irqd_to_hwirq(d);
>> + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
>> + struct irq_chip_type *ct = irq_data_get_chip_type(d);
>>
>> switch (flow_type & IRQ_TYPE_SENSE_MASK) {
>> case IRQ_TYPE_EDGE_FALLING:
>> - setbits32(data->reg + CEPICR, 1 << (31 - vec));
>> + setbits32(gc->reg_base + ct->regs.type, d->mask);
>> return 0;
>> case IRQ_TYPE_EDGE_BOTH:
>> case IRQ_TYPE_NONE:
>> - clrbits32(data->reg + CEPICR, 1 << (31 - vec));
>> + clrbits32(gc->reg_base + ct->regs.type, d->mask);
>> return 0;
>> }
>> return -EINVAL;
>> }
>>
>> -static struct irq_chip qepic = {
>> - .name = "QEPIC",
>> - .irq_mask = qepic_mask,
>> - .irq_unmask = qepic_unmask,
>> - .irq_eoi = qepic_end,
>> - .irq_set_type = qepic_set_type,
>> -};
>> -
>> static void qepic_cascade(struct irq_desc *desc)
>> {
>> struct qepic_data *data = irq_desc_get_handler_data(desc);
>> + struct irq_chip_type *ct = data->gc->chip_types;
>> struct irq_chip *chip = irq_desc_get_chip(desc);
>> unsigned long event, bit;
>>
>> chained_irq_enter(chip, desc);
>>
>> - event = in_be32(data->reg + CEPIER);
>> + event = in_be32(data->gc->reg_base + ct->regs.eoi);
>> if (!event) {
>> handle_bad_irq(desc);
>> goto out;
>> @@ -89,33 +91,64 @@ static void qepic_cascade(struct irq_desc *desc)
>> chained_irq_exit(chip, desc);
>> }
>>
>> -static int qepic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw)
>> +static int qepic_chip_init(struct irq_chip_generic *gc)
>> {
>> - irq_set_chip_data(virq, h->host_data);
>> - irq_set_chip_and_handler(virq, &qepic, handle_fasteoi_irq);
>> + struct irq_chip_type *ct = gc->chip_types;
>> +
>> + ct->regs.mask = CEPIMR;
>> + ct->chip.irq_mask = qepic_mask;
>> + ct->chip.irq_unmask = qepic_unmask;
>> + ct->regs.eoi = CEPIER;
>> + ct->chip.irq_eoi = qepic_end;
>> + ct->regs.type = CEPICR;
>> + ct->chip.irq_set_type = qepic_set_type;
>> + ct->chip.irq_calc_mask = qepic_calc_mask;
>
> Are ct->regs.mask, ct->regs.eoi and ct->regs.type used anywhere else
> than locally in qepic_{mask/unmask/end/set_type} ?
No they are not.
The main purpose of these registers is that they are used in the generic irq
chip framework functions like irq_gc_mask_set_bit(), which we dropped earlier in
favor of using our own hooks.
At this stage, if you consider that the instructions overhead of the functions
above is already too much, it is better to get rid of the framework completly
then.
>
> Christophe
>
>> +
>> return 0;
>> }
>>
>> -static const struct irq_domain_ops qepic_host_ops = {
>> - .map = qepic_host_map,
>> -};
>> +static int qepic_domain_init(struct irq_domain *d)
>> +{
>> + struct qepic_data *data = d->host_data;
>>
>> -static void qepic_remove(void *res)
>> + irq_set_chained_handler_and_data(data->irq, qepic_cascade, data);
>> +
>> + return 0;
>> +}
>> +
>> +static void qepic_domain_exit(struct irq_domain *d)
>> {
>> - struct qepic_data *data = res;
>> + struct qepic_data *data = d->host_data;
>>
>> irq_set_chained_handler_and_data(data->irq, NULL, NULL);
>> - irq_domain_remove(data->host);
>> }
>>
>> static int qepic_probe(struct platform_device *pdev)
>> {
>> + struct irq_domain_chip_generic_info dgc_info = {
>> + .name = "QEPIC",
>> + .handler = handle_fasteoi_irq,
>> + .irqs_per_chip = 32,
>> + .num_ct = 1,
>> + .init = qepic_chip_init,
>> + };
>> + struct irq_domain_info d_info = {
>> + .fwnode = of_fwnode_handle(pdev->dev.of_node),
>> + .domain_flags = IRQ_DOMAIN_FLAG_DESTROY_GC,
>> + .size = 32,
>> + .hwirq_max = 32,
>> + .ops = &irq_generic_chip_ops,
>> + .dgc_info = &dgc_info,
>> + .init = qepic_domain_init,
>> + .exit = qepic_domain_exit,
>> + };
>> struct device *dev = &pdev->dev;
>> struct qepic_data *data;
>>
>> data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
>> if (!data)
>> return -ENOMEM;
>> + d_info.host_data = data;
>>
>> data->reg = devm_platform_ioremap_resource(pdev, 0);
>> if (IS_ERR(data->reg))
>> @@ -125,14 +158,16 @@ static int qepic_probe(struct platform_device *pdev)
>> if (data->irq < 0)
>> return data->irq;
>>
>> - data->host = irq_domain_create_linear(dev_fwnode(dev), 32, &qepic_host_ops, data);
>> - if (!data->host)
>> - return -ENODEV;
>> + data->host = devm_irq_domain_instantiate(dev, &d_info);
>> + if (IS_ERR(data->host))
>> + return PTR_ERR(data->host);
>>
>> - irq_set_chained_handler_and_data(data->irq, qepic_cascade, data);
>> -
>> - return devm_add_action_or_reset(dev, qepic_remove, data);
>> + data->gc = irq_get_domain_generic_chip(data->host, 0);
>> + if (!data->gc)
>> + return -ENODEV;
>> + data->gc->reg_base = data->reg;
>>
>> + return 0;
>> }
>>
>> static const struct of_device_id qepic_match[] = {
>>
Thanks,
Paul.
--
Paul Louvel, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 09/12] soc: fsl: qe: Rename irq variable to parent_irq
2026-07-03 13:30 [PATCH 00/12] soc: fsl: qe: QE PIC improvement and add support of IRQs to QUICC ENGINE GPIOs Paul Louvel
` (7 preceding siblings ...)
2026-07-03 13:30 ` [PATCH 08/12] soc: fsl: qe: Convert to generic IRQ chip Paul Louvel
@ 2026-07-03 13:30 ` Paul Louvel
2026-07-03 13:30 ` [PATCH 10/12] soc: fsl: qe: Rename host member to domain in struct qepic_data Paul Louvel
` (2 subsequent siblings)
11 siblings, 0 replies; 19+ messages in thread
From: Paul Louvel @ 2026-07-03 13:30 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Thomas Petazzoni
Rename the local variable holding the platform IRQ to parent_irq, which
better describes its role as the upstream/chained interrupt in the
hierarchy.
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
drivers/soc/fsl/qe/qe_ports_ic.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c
index d022aa224f6d..718703dab024 100644
--- a/drivers/soc/fsl/qe/qe_ports_ic.c
+++ b/drivers/soc/fsl/qe/qe_ports_ic.c
@@ -19,7 +19,7 @@
struct qepic_data {
void __iomem *reg;
struct irq_domain *host;
- int irq;
+ int parent_irq;
struct irq_chip_generic *gc;
};
@@ -111,7 +111,7 @@ static int qepic_domain_init(struct irq_domain *d)
{
struct qepic_data *data = d->host_data;
- irq_set_chained_handler_and_data(data->irq, qepic_cascade, data);
+ irq_set_chained_handler_and_data(data->parent_irq, qepic_cascade, data);
return 0;
}
@@ -120,7 +120,7 @@ static void qepic_domain_exit(struct irq_domain *d)
{
struct qepic_data *data = d->host_data;
- irq_set_chained_handler_and_data(data->irq, NULL, NULL);
+ irq_set_chained_handler_and_data(data->parent_irq, NULL, NULL);
}
static int qepic_probe(struct platform_device *pdev)
@@ -154,9 +154,9 @@ static int qepic_probe(struct platform_device *pdev)
if (IS_ERR(data->reg))
return PTR_ERR(data->reg);
- data->irq = platform_get_irq(pdev, 0);
- if (data->irq < 0)
- return data->irq;
+ data->parent_irq = platform_get_irq(pdev, 0);
+ if (data->parent_irq < 0)
+ return data->parent_irq;
data->host = devm_irq_domain_instantiate(dev, &d_info);
if (IS_ERR(data->host))
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH 10/12] soc: fsl: qe: Rename host member to domain in struct qepic_data
2026-07-03 13:30 [PATCH 00/12] soc: fsl: qe: QE PIC improvement and add support of IRQs to QUICC ENGINE GPIOs Paul Louvel
` (8 preceding siblings ...)
2026-07-03 13:30 ` [PATCH 09/12] soc: fsl: qe: Rename irq variable to parent_irq Paul Louvel
@ 2026-07-03 13:30 ` Paul Louvel
2026-07-03 13:30 ` [PATCH 11/12] soc: fsl: qe: Remove useless struct member Paul Louvel
2026-07-03 13:30 ` [PATCH 12/12] soc: fsl: qe: Add support of IRQs in QE GPIO Paul Louvel
11 siblings, 0 replies; 19+ messages in thread
From: Paul Louvel @ 2026-07-03 13:30 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Thomas Petazzoni
Rename the host field to domain to match the common kernel naming
convention for irq_domain pointers.
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
drivers/soc/fsl/qe/qe_ports_ic.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c
index 718703dab024..1bf2af087b78 100644
--- a/drivers/soc/fsl/qe/qe_ports_ic.c
+++ b/drivers/soc/fsl/qe/qe_ports_ic.c
@@ -18,8 +18,8 @@
struct qepic_data {
void __iomem *reg;
- struct irq_domain *host;
int parent_irq;
+ struct irq_domain *domain;
struct irq_chip_generic *gc;
};
@@ -85,7 +85,7 @@ static void qepic_cascade(struct irq_desc *desc)
}
for_each_set_bit(bit, &event, 32)
- generic_handle_domain_irq(data->host, 32 - bit);
+ generic_handle_domain_irq(data->domain, 32 - bit);
out:
chained_irq_exit(chip, desc);
@@ -158,11 +158,11 @@ static int qepic_probe(struct platform_device *pdev)
if (data->parent_irq < 0)
return data->parent_irq;
- data->host = devm_irq_domain_instantiate(dev, &d_info);
- if (IS_ERR(data->host))
- return PTR_ERR(data->host);
+ data->domain = devm_irq_domain_instantiate(dev, &d_info);
+ if (IS_ERR(data->domain))
+ return PTR_ERR(data->domain);
- data->gc = irq_get_domain_generic_chip(data->host, 0);
+ data->gc = irq_get_domain_generic_chip(data->domain, 0);
if (!data->gc)
return -ENODEV;
data->gc->reg_base = data->reg;
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH 11/12] soc: fsl: qe: Remove useless struct member
2026-07-03 13:30 [PATCH 00/12] soc: fsl: qe: QE PIC improvement and add support of IRQs to QUICC ENGINE GPIOs Paul Louvel
` (9 preceding siblings ...)
2026-07-03 13:30 ` [PATCH 10/12] soc: fsl: qe: Rename host member to domain in struct qepic_data Paul Louvel
@ 2026-07-03 13:30 ` Paul Louvel
2026-07-03 13:30 ` [PATCH 12/12] soc: fsl: qe: Add support of IRQs in QE GPIO Paul Louvel
11 siblings, 0 replies; 19+ messages in thread
From: Paul Louvel @ 2026-07-03 13:30 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Thomas Petazzoni
The reg member from the struct qepic_data is no longer needed, since it
is now embedded in reg_base of struct irq_chip_generic. Remove it.
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
drivers/soc/fsl/qe/qe_ports_ic.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c
index 1bf2af087b78..6cf23a721ff3 100644
--- a/drivers/soc/fsl/qe/qe_ports_ic.c
+++ b/drivers/soc/fsl/qe/qe_ports_ic.c
@@ -17,7 +17,6 @@
#define CEPICR 0x14
struct qepic_data {
- void __iomem *reg;
int parent_irq;
struct irq_domain *domain;
struct irq_chip_generic *gc;
@@ -144,15 +143,16 @@ static int qepic_probe(struct platform_device *pdev)
};
struct device *dev = &pdev->dev;
struct qepic_data *data;
+ void __iomem *reg;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
d_info.host_data = data;
- data->reg = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(data->reg))
- return PTR_ERR(data->reg);
+ reg = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
data->parent_irq = platform_get_irq(pdev, 0);
if (data->parent_irq < 0)
@@ -165,7 +165,7 @@ static int qepic_probe(struct platform_device *pdev)
data->gc = irq_get_domain_generic_chip(data->domain, 0);
if (!data->gc)
return -ENODEV;
- data->gc->reg_base = data->reg;
+ data->gc->reg_base = reg;
return 0;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [PATCH 12/12] soc: fsl: qe: Add support of IRQs in QE GPIO
2026-07-03 13:30 [PATCH 00/12] soc: fsl: qe: QE PIC improvement and add support of IRQs to QUICC ENGINE GPIOs Paul Louvel
` (10 preceding siblings ...)
2026-07-03 13:30 ` [PATCH 11/12] soc: fsl: qe: Remove useless struct member Paul Louvel
@ 2026-07-03 13:30 ` Paul Louvel
11 siblings, 0 replies; 19+ messages in thread
From: Paul Louvel @ 2026-07-03 13:30 UTC (permalink / raw)
To: Qiang Zhao, Christophe Leroy (CS GROUP), Thomas Gleixner,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin
Cc: linuxppc-dev, linux-arm-kernel, linux-kernel, devicetree,
linux-gpio, Paul Louvel, Thomas Petazzoni
Some QE GPIO pins have an associated interrupt line in the QE PIC to
signal state changes on the pin.
Because the GPIO controller does not perform any interrupt handling
itself, a nexus node (interrupt-map) is used to map each GPIO line
supporting IRQ to the parent QE PIC interrupt domain.
Add the to_irq() method in the corresponding GPIO controller driver,
that uses the nexus node to perform the translation.
Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
---
drivers/soc/fsl/qe/gpio.c | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/drivers/soc/fsl/qe/gpio.c b/drivers/soc/fsl/qe/gpio.c
index 66828f2a3577..f8919642f40d 100644
--- a/drivers/soc/fsl/qe/gpio.c
+++ b/drivers/soc/fsl/qe/gpio.c
@@ -16,6 +16,7 @@
#include <linux/gpio/driver.h>
#include <linux/slab.h>
#include <linux/export.h>
+#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <soc/fsl/qe/qe.h>
@@ -23,6 +24,7 @@
#define PIN_MASK(gpio) (1UL << (QE_PIO_PINS - 1 - (gpio)))
struct qe_gpio_chip {
+ struct device_node *np;
struct gpio_chip gc;
void __iomem *regs;
spinlock_t lock;
@@ -135,6 +137,29 @@ static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
return 0;
}
+static int qe_gpio_to_irq(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc);
+ struct of_phandle_args oirq;
+ struct irq_domain *domain;
+ int ret;
+
+ oirq.np = qe_gc->np;
+ oirq.args_count = 2;
+ oirq.args[0] = gpio;
+ oirq.args[1] = 0;
+
+ ret = of_irq_parse_raw(NULL, &oirq);
+ if (ret)
+ return ret;
+
+ domain = irq_find_host(oirq.np);
+ if (!domain)
+ return -EPROBE_DEFER;
+
+ return irq_create_of_mapping(&oirq);
+}
+
struct qe_pin {
/*
* The qe_gpio_chip name is unfortunate, we should change that to
@@ -299,7 +324,7 @@ static int qe_gpio_probe(struct platform_device *ofdev)
qe_gc = devm_kzalloc(dev, sizeof(*qe_gc), GFP_KERNEL);
if (!qe_gc)
return -ENOMEM;
-
+ qe_gc->np = np;
spin_lock_init(&qe_gc->lock);
gc = &qe_gc->gc;
@@ -311,6 +336,7 @@ static int qe_gpio_probe(struct platform_device *ofdev)
gc->get = qe_gpio_get;
gc->set = qe_gpio_set;
gc->set_multiple = qe_gpio_set_multiple;
+ gc->to_irq = qe_gpio_to_irq;
gc->parent = dev;
gc->owner = THIS_MODULE;
--
2.55.0
^ permalink raw reply related [flat|nested] 19+ messages in thread