All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/10] sunxi: Support IRQ wakeup from deep sleep
@ 2021-01-03 10:30 ` Samuel Holland
  0 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel,
	linux-sunxi, Samuel Holland

Allwinner sun6i/sun8i/sun50i SoCs (A31 and newer) have two interrupt
controllers: GIC and R_INTC. GIC does not support wakeup. R_INTC handles
the external NMI pin, and provides 32+ IRQs to the ARISC. The first 16
of these correspond 1:1 to a block of GIC IRQs starting with the NMI.
The last 13-16 multiplex the first (up to) 128 GIC SPIs.

This series replaces the existing chained irqchip driver that could only
control the NMI, with a stacked irqchip driver that also provides wakeup
capability for those multiplexed SPI IRQs. The idea is to preconfigure
the ARISC's IRQ controller, and then the ARISC firmware knows to wake up
as soon as it receives an IRQ. It can also decide how deep it can
suspend based on the selected wakeup IRQs.

As future work, it may be useful to do the chained->stacked conversion
on the sunxi-nmi driver as well.

Patches 1-2 add the new bindings.
Patch 3 adds the new driver.
Patch 4 adds wakeup capability.
The other patches update the device trees to use R_INTC where beneficial.

With appropriate firmware and configuration, this series allows waking
from (and it has been tested with) the RTC, NMI/PMIC (power button, A/C
plug, etc.), all GPIO ports (button, lid switch, modem, etc.), LRADC,
and UARTs. I have tested this patch set on the H3, A64, H5, and H6 SoCs.

---

Changes from v2:
 - Fix edge IRQs on GICv2 with EOImode == 0, as found on A83T and older.
   - Replace .irq_ack callback with .irq_mask.
   - Drop IRQCHIP_EOI_THREADED.
   - This removes the dependency on IRQ_FASTEOI_HIERARCHY_HANDLERS.
 - Move IRQ_DOMAIN_HIERARCHY selection to ARCH_SUNXI to fix A83T build.
 - Add support for the second IRQ ENABLE/PENDING register on H6 and up.
 - Add support for multiplexed IRQs beyond the initial 16.
   - This requires a new binding, but keeps old binding compatibility.
   - This requires a separate mux mapping for H6 and up.
 - Rename parent_* => nmi_* because they only apply to the NMI.
 - Merge code common to probe and resume functions.
 - Also run suspend callback at syscore shutdown, for boards with no
   PMIC where firmware is also responsible for poweroff/poweron.
   - These two changes mean nothing is conditional on CONFIG_PM_SLEEP
     anymore, since all code is used even without it.
 - Since the binding changed, update all SoC DTs, A31 and up.
 - Drop r_ir from inclusion (it needs more than an IRQ to wake) and
   include pio (the main pin controller) and (r_)lradc.
 - As there are significant changes, I did not carry forward Maxime's
   Acked-by or Rob's Reviewed-by.

Changes from v1:
 - Use writel_relaxed() instead if writel().
 - Remove use of the MASK register, as it doesn't affect the NMI as seen
   by the GIC. It only affects the IRQs seen by the coprocessor.
 - Leave NMI_HWIRQ enabled at all times, since it can be masked at the
   GIC level (removed .irq_enable and .irq_disable).
 - Use .irq_ack vs .irq_eoi depending on the trigger type, to avoid
   missing interrupts or double interrupts.
   - Because of this change, the driver needs two "irq_chip"s, one
     with .irq_eoi set to our function and one without.
   - Also because of this, we need IRQ_FASTEOI_HIERARCHY_HANDLERS for
     handle_fasteoi_ack_irq(), so our .irq_ack function gets called
     while the GIC driver works as if handle_fasteoi_irq() was used.
 - Inline the SUNXI_SRC_TYPE_* enum into sun6i_r_intc_irq_set_type().
 - Add a comment explaining how the trigger type is used.
 - Don't call irqd_set_trigger_type().
 - Set IRQCHIP_SET_TYPE_MASKED to match the GIC (since flags from this
   driver mask flags from that one).
 - Set IRQCHIP_EOI_THREADED to avoid doubled level interrupts, since the
   latch will be set again as long as the trigger is met.
 - Replace sun6i_r_intc_domain_translate() with
   irq_domain_translate_twocell().
 - Use an enum for the device tree binding.
 - Update commit messages for accuracy and typos.

Samuel Holland (10):
  dt-bindings: irq: sun6i-r: Split the binding from sun7i-nmi
  dt-bindings: irq: sun6i-r: Add a compatible for the H3
  irqchip/sun6i-r: Use a stacked irqchip driver
  irqchip/sun6i-r: Add wakeup support
  ARM: dts: sunxi: Rename nmi_intc to r_intc
  ARM: dts: sunxi: Use the new r_intc binding
  ARM: dts: sunxi: h3/h5: Add r_intc node
  ARM: dts: sunxi: Move wakeup-capable IRQs to r_intc
  arm64: dts: allwinner: Use the new r_intc binding
  arm64: dts: allwinner: Move wakeup-capable IRQs to r_intc

 .../allwinner,sun6i-a31-r-intc.yaml           |  65 ++++
 .../allwinner,sun7i-a20-sc-nmi.yaml           |  10 -
 arch/arm/boot/dts/sun6i-a31-hummingbird.dts   |   4 +-
 arch/arm/boot/dts/sun6i-a31-m9.dts            |   4 +-
 .../boot/dts/sun6i-a31-mele-a1000g-quad.dts   |   4 +-
 arch/arm/boot/dts/sun6i-a31.dtsi              |   8 +-
 arch/arm/boot/dts/sun6i-a31s-primo81.dts      |   4 +-
 .../arm/boot/dts/sun6i-a31s-sina31s-core.dtsi |   4 +-
 .../boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts   |   4 +-
 .../sun6i-a31s-yones-toptech-bs1078-v2.dts    |   4 +-
 .../dts/sun6i-reference-design-tablet.dtsi    |   4 +-
 arch/arm/boot/dts/sun8i-a23-a33.dtsi          |   8 +-
 arch/arm/boot/dts/sun8i-a33-olinuxino.dts     |   4 +-
 .../arm/boot/dts/sun8i-a33-sinlinx-sina33.dts |   4 +-
 .../dts/sun8i-a83t-allwinner-h8homlet-v2.dts  |   4 +-
 arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts  |   4 +-
 .../boot/dts/sun8i-a83t-cubietruck-plus.dts   |   4 +-
 arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts     |   4 +-
 arch/arm/boot/dts/sun8i-a83t.dtsi             |   5 +-
 arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts  |   4 +-
 arch/arm/boot/dts/sun8i-r16-parrot.dts        |   4 +-
 .../dts/sun8i-reference-design-tablet.dtsi    |   4 +-
 arch/arm/boot/dts/sunxi-h3-h5.dtsi            |  12 +
 arch/arm/mach-sunxi/Kconfig                   |   1 +
 arch/arm64/Kconfig.platforms                  |   1 +
 .../allwinner/sun50i-a64-amarula-relic.dts    |   2 +-
 .../dts/allwinner/sun50i-a64-bananapi-m64.dts |   2 +-
 .../dts/allwinner/sun50i-a64-nanopi-a64.dts   |   2 +-
 .../dts/allwinner/sun50i-a64-olinuxino.dts    |   2 +-
 .../dts/allwinner/sun50i-a64-orangepi-win.dts |   2 +-
 .../boot/dts/allwinner/sun50i-a64-pine64.dts  |   2 +-
 .../dts/allwinner/sun50i-a64-pinebook.dts     |   2 +-
 .../dts/allwinner/sun50i-a64-pinephone.dtsi   |   2 +-
 .../boot/dts/allwinner/sun50i-a64-pinetab.dts |   2 +-
 .../boot/dts/allwinner/sun50i-a64-sopine.dtsi |   2 +-
 .../boot/dts/allwinner/sun50i-a64-teres-i.dts |   2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi |   6 +-
 .../dts/allwinner/sun50i-h6-beelink-gs1.dts   |   2 +-
 .../dts/allwinner/sun50i-h6-orangepi-3.dts    |   2 +-
 .../dts/allwinner/sun50i-h6-orangepi.dtsi     |   2 +-
 .../boot/dts/allwinner/sun50i-h6-pine-h64.dts |   4 +-
 arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi  |   5 +-
 drivers/irqchip/Makefile                      |   1 +
 drivers/irqchip/irq-sun6i-r.c                 | 353 ++++++++++++++++++
 drivers/irqchip/irq-sunxi-nmi.c               |  26 +-
 45 files changed, 511 insertions(+), 90 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml
 create mode 100644 drivers/irqchip/irq-sun6i-r.c

-- 
2.26.2


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v3 00/10] sunxi: Support IRQ wakeup from deep sleep
@ 2021-01-03 10:30 ` Samuel Holland
  0 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, Samuel Holland, linux-kernel,
	linux-sunxi, linux-arm-kernel

Allwinner sun6i/sun8i/sun50i SoCs (A31 and newer) have two interrupt
controllers: GIC and R_INTC. GIC does not support wakeup. R_INTC handles
the external NMI pin, and provides 32+ IRQs to the ARISC. The first 16
of these correspond 1:1 to a block of GIC IRQs starting with the NMI.
The last 13-16 multiplex the first (up to) 128 GIC SPIs.

This series replaces the existing chained irqchip driver that could only
control the NMI, with a stacked irqchip driver that also provides wakeup
capability for those multiplexed SPI IRQs. The idea is to preconfigure
the ARISC's IRQ controller, and then the ARISC firmware knows to wake up
as soon as it receives an IRQ. It can also decide how deep it can
suspend based on the selected wakeup IRQs.

As future work, it may be useful to do the chained->stacked conversion
on the sunxi-nmi driver as well.

Patches 1-2 add the new bindings.
Patch 3 adds the new driver.
Patch 4 adds wakeup capability.
The other patches update the device trees to use R_INTC where beneficial.

With appropriate firmware and configuration, this series allows waking
from (and it has been tested with) the RTC, NMI/PMIC (power button, A/C
plug, etc.), all GPIO ports (button, lid switch, modem, etc.), LRADC,
and UARTs. I have tested this patch set on the H3, A64, H5, and H6 SoCs.

---

Changes from v2:
 - Fix edge IRQs on GICv2 with EOImode == 0, as found on A83T and older.
   - Replace .irq_ack callback with .irq_mask.
   - Drop IRQCHIP_EOI_THREADED.
   - This removes the dependency on IRQ_FASTEOI_HIERARCHY_HANDLERS.
 - Move IRQ_DOMAIN_HIERARCHY selection to ARCH_SUNXI to fix A83T build.
 - Add support for the second IRQ ENABLE/PENDING register on H6 and up.
 - Add support for multiplexed IRQs beyond the initial 16.
   - This requires a new binding, but keeps old binding compatibility.
   - This requires a separate mux mapping for H6 and up.
 - Rename parent_* => nmi_* because they only apply to the NMI.
 - Merge code common to probe and resume functions.
 - Also run suspend callback at syscore shutdown, for boards with no
   PMIC where firmware is also responsible for poweroff/poweron.
   - These two changes mean nothing is conditional on CONFIG_PM_SLEEP
     anymore, since all code is used even without it.
 - Since the binding changed, update all SoC DTs, A31 and up.
 - Drop r_ir from inclusion (it needs more than an IRQ to wake) and
   include pio (the main pin controller) and (r_)lradc.
 - As there are significant changes, I did not carry forward Maxime's
   Acked-by or Rob's Reviewed-by.

Changes from v1:
 - Use writel_relaxed() instead if writel().
 - Remove use of the MASK register, as it doesn't affect the NMI as seen
   by the GIC. It only affects the IRQs seen by the coprocessor.
 - Leave NMI_HWIRQ enabled at all times, since it can be masked at the
   GIC level (removed .irq_enable and .irq_disable).
 - Use .irq_ack vs .irq_eoi depending on the trigger type, to avoid
   missing interrupts or double interrupts.
   - Because of this change, the driver needs two "irq_chip"s, one
     with .irq_eoi set to our function and one without.
   - Also because of this, we need IRQ_FASTEOI_HIERARCHY_HANDLERS for
     handle_fasteoi_ack_irq(), so our .irq_ack function gets called
     while the GIC driver works as if handle_fasteoi_irq() was used.
 - Inline the SUNXI_SRC_TYPE_* enum into sun6i_r_intc_irq_set_type().
 - Add a comment explaining how the trigger type is used.
 - Don't call irqd_set_trigger_type().
 - Set IRQCHIP_SET_TYPE_MASKED to match the GIC (since flags from this
   driver mask flags from that one).
 - Set IRQCHIP_EOI_THREADED to avoid doubled level interrupts, since the
   latch will be set again as long as the trigger is met.
 - Replace sun6i_r_intc_domain_translate() with
   irq_domain_translate_twocell().
 - Use an enum for the device tree binding.
 - Update commit messages for accuracy and typos.

Samuel Holland (10):
  dt-bindings: irq: sun6i-r: Split the binding from sun7i-nmi
  dt-bindings: irq: sun6i-r: Add a compatible for the H3
  irqchip/sun6i-r: Use a stacked irqchip driver
  irqchip/sun6i-r: Add wakeup support
  ARM: dts: sunxi: Rename nmi_intc to r_intc
  ARM: dts: sunxi: Use the new r_intc binding
  ARM: dts: sunxi: h3/h5: Add r_intc node
  ARM: dts: sunxi: Move wakeup-capable IRQs to r_intc
  arm64: dts: allwinner: Use the new r_intc binding
  arm64: dts: allwinner: Move wakeup-capable IRQs to r_intc

 .../allwinner,sun6i-a31-r-intc.yaml           |  65 ++++
 .../allwinner,sun7i-a20-sc-nmi.yaml           |  10 -
 arch/arm/boot/dts/sun6i-a31-hummingbird.dts   |   4 +-
 arch/arm/boot/dts/sun6i-a31-m9.dts            |   4 +-
 .../boot/dts/sun6i-a31-mele-a1000g-quad.dts   |   4 +-
 arch/arm/boot/dts/sun6i-a31.dtsi              |   8 +-
 arch/arm/boot/dts/sun6i-a31s-primo81.dts      |   4 +-
 .../arm/boot/dts/sun6i-a31s-sina31s-core.dtsi |   4 +-
 .../boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts   |   4 +-
 .../sun6i-a31s-yones-toptech-bs1078-v2.dts    |   4 +-
 .../dts/sun6i-reference-design-tablet.dtsi    |   4 +-
 arch/arm/boot/dts/sun8i-a23-a33.dtsi          |   8 +-
 arch/arm/boot/dts/sun8i-a33-olinuxino.dts     |   4 +-
 .../arm/boot/dts/sun8i-a33-sinlinx-sina33.dts |   4 +-
 .../dts/sun8i-a83t-allwinner-h8homlet-v2.dts  |   4 +-
 arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts  |   4 +-
 .../boot/dts/sun8i-a83t-cubietruck-plus.dts   |   4 +-
 arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts     |   4 +-
 arch/arm/boot/dts/sun8i-a83t.dtsi             |   5 +-
 arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts  |   4 +-
 arch/arm/boot/dts/sun8i-r16-parrot.dts        |   4 +-
 .../dts/sun8i-reference-design-tablet.dtsi    |   4 +-
 arch/arm/boot/dts/sunxi-h3-h5.dtsi            |  12 +
 arch/arm/mach-sunxi/Kconfig                   |   1 +
 arch/arm64/Kconfig.platforms                  |   1 +
 .../allwinner/sun50i-a64-amarula-relic.dts    |   2 +-
 .../dts/allwinner/sun50i-a64-bananapi-m64.dts |   2 +-
 .../dts/allwinner/sun50i-a64-nanopi-a64.dts   |   2 +-
 .../dts/allwinner/sun50i-a64-olinuxino.dts    |   2 +-
 .../dts/allwinner/sun50i-a64-orangepi-win.dts |   2 +-
 .../boot/dts/allwinner/sun50i-a64-pine64.dts  |   2 +-
 .../dts/allwinner/sun50i-a64-pinebook.dts     |   2 +-
 .../dts/allwinner/sun50i-a64-pinephone.dtsi   |   2 +-
 .../boot/dts/allwinner/sun50i-a64-pinetab.dts |   2 +-
 .../boot/dts/allwinner/sun50i-a64-sopine.dtsi |   2 +-
 .../boot/dts/allwinner/sun50i-a64-teres-i.dts |   2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi |   6 +-
 .../dts/allwinner/sun50i-h6-beelink-gs1.dts   |   2 +-
 .../dts/allwinner/sun50i-h6-orangepi-3.dts    |   2 +-
 .../dts/allwinner/sun50i-h6-orangepi.dtsi     |   2 +-
 .../boot/dts/allwinner/sun50i-h6-pine-h64.dts |   4 +-
 arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi  |   5 +-
 drivers/irqchip/Makefile                      |   1 +
 drivers/irqchip/irq-sun6i-r.c                 | 353 ++++++++++++++++++
 drivers/irqchip/irq-sunxi-nmi.c               |  26 +-
 45 files changed, 511 insertions(+), 90 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml
 create mode 100644 drivers/irqchip/irq-sun6i-r.c

-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v3 01/10] dt-bindings: irq: sun6i-r: Split the binding from sun7i-nmi
  2021-01-03 10:30 ` Samuel Holland
@ 2021-01-03 10:30   ` Samuel Holland
  -1 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel,
	linux-sunxi, Samuel Holland

The R_INTC in the A31 and newer sun8i/sun50i SoCs has additional
functionality compared to the sun7i/sun9i NMI controller. Among other
things, it multiplexes up to 128 interrupts corresponding to (and in
parallel to) the first 128 GIC SPIs. This means the NMI is no longer the
lowest-numbered interrupt, since it is SPI 32 or 96 (depending on SoC).

To allow access to all multiplexed IRQs, the R_INTC requires a new
binding where the interrupt number matches the GIC interrupt number.
For simplicity, copy the three-cell GIC binding; this disambiguates
interrupt 0 in the old binding (the NMI) from interrupt 0 in the new
binding (SPI 0) by the number of cells.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 .../allwinner,sun6i-a31-r-intc.yaml           | 64 +++++++++++++++++++
 .../allwinner,sun7i-a20-sc-nmi.yaml           | 10 ---
 2 files changed, 64 insertions(+), 10 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml

diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml
new file mode 100644
index 000000000000..18805b6555c2
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A31 NMI/Wakeup Interrupt Controller Device Tree Bindings
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <mripard@kernel.org>
+
+allOf:
+  - $ref: /schemas/interrupt-controller.yaml#
+
+properties:
+  "#interrupt-cells":
+    const: 3
+    description:
+      The first cell is GIC_SPI (0), the second cell is the IRQ number, and
+      the third cell is the trigger type as defined in interrupt.txt in this
+      directory.
+
+  compatible:
+    oneOf:
+      - items:
+          - enum:
+              - allwinner,sun8i-a83t-r-intc
+              - allwinner,sun50i-a64-r-intc
+              - allwinner,sun50i-h6-r-intc
+          - const: allwinner,sun6i-a31-r-intc
+      - const: allwinner,sun6i-a31-r-intc
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+required:
+  - "#interrupt-cells"
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-controller
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    r_intc: interrupt-controller@1f00c00 {
+            compatible = "allwinner,sun50i-a64-r-intc",
+                         "allwinner,sun6i-a31-r-intc";
+            interrupt-controller;
+            #interrupt-cells = <3>;
+            reg = <0x01f00c00 0x400>;
+            interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml
index 8acca0ae3129..f34ecc8c7093 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml
@@ -22,23 +22,13 @@ properties:
 
   compatible:
     oneOf:
-      - const: allwinner,sun6i-a31-r-intc
       - const: allwinner,sun6i-a31-sc-nmi
         deprecated: true
       - const: allwinner,sun7i-a20-sc-nmi
-      - items:
-          - const: allwinner,sun8i-a83t-r-intc
-          - const: allwinner,sun6i-a31-r-intc
       - const: allwinner,sun9i-a80-nmi
-      - items:
-          - const: allwinner,sun50i-a64-r-intc
-          - const: allwinner,sun6i-a31-r-intc
       - items:
           - const: allwinner,sun50i-a100-nmi
           - const: allwinner,sun9i-a80-nmi
-      - items:
-          - const: allwinner,sun50i-h6-r-intc
-          - const: allwinner,sun6i-a31-r-intc
 
   reg:
     maxItems: 1
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 01/10] dt-bindings: irq: sun6i-r: Split the binding from sun7i-nmi
@ 2021-01-03 10:30   ` Samuel Holland
  0 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, Samuel Holland, linux-kernel,
	linux-sunxi, linux-arm-kernel

The R_INTC in the A31 and newer sun8i/sun50i SoCs has additional
functionality compared to the sun7i/sun9i NMI controller. Among other
things, it multiplexes up to 128 interrupts corresponding to (and in
parallel to) the first 128 GIC SPIs. This means the NMI is no longer the
lowest-numbered interrupt, since it is SPI 32 or 96 (depending on SoC).

To allow access to all multiplexed IRQs, the R_INTC requires a new
binding where the interrupt number matches the GIC interrupt number.
For simplicity, copy the three-cell GIC binding; this disambiguates
interrupt 0 in the old binding (the NMI) from interrupt 0 in the new
binding (SPI 0) by the number of cells.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 .../allwinner,sun6i-a31-r-intc.yaml           | 64 +++++++++++++++++++
 .../allwinner,sun7i-a20-sc-nmi.yaml           | 10 ---
 2 files changed, 64 insertions(+), 10 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml

diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml
new file mode 100644
index 000000000000..18805b6555c2
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A31 NMI/Wakeup Interrupt Controller Device Tree Bindings
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <mripard@kernel.org>
+
+allOf:
+  - $ref: /schemas/interrupt-controller.yaml#
+
+properties:
+  "#interrupt-cells":
+    const: 3
+    description:
+      The first cell is GIC_SPI (0), the second cell is the IRQ number, and
+      the third cell is the trigger type as defined in interrupt.txt in this
+      directory.
+
+  compatible:
+    oneOf:
+      - items:
+          - enum:
+              - allwinner,sun8i-a83t-r-intc
+              - allwinner,sun50i-a64-r-intc
+              - allwinner,sun50i-h6-r-intc
+          - const: allwinner,sun6i-a31-r-intc
+      - const: allwinner,sun6i-a31-r-intc
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+required:
+  - "#interrupt-cells"
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-controller
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    r_intc: interrupt-controller@1f00c00 {
+            compatible = "allwinner,sun50i-a64-r-intc",
+                         "allwinner,sun6i-a31-r-intc";
+            interrupt-controller;
+            #interrupt-cells = <3>;
+            reg = <0x01f00c00 0x400>;
+            interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml
index 8acca0ae3129..f34ecc8c7093 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml
@@ -22,23 +22,13 @@ properties:
 
   compatible:
     oneOf:
-      - const: allwinner,sun6i-a31-r-intc
       - const: allwinner,sun6i-a31-sc-nmi
         deprecated: true
       - const: allwinner,sun7i-a20-sc-nmi
-      - items:
-          - const: allwinner,sun8i-a83t-r-intc
-          - const: allwinner,sun6i-a31-r-intc
       - const: allwinner,sun9i-a80-nmi
-      - items:
-          - const: allwinner,sun50i-a64-r-intc
-          - const: allwinner,sun6i-a31-r-intc
       - items:
           - const: allwinner,sun50i-a100-nmi
           - const: allwinner,sun9i-a80-nmi
-      - items:
-          - const: allwinner,sun50i-h6-r-intc
-          - const: allwinner,sun6i-a31-r-intc
 
   reg:
     maxItems: 1
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 02/10] dt-bindings: irq: sun6i-r: Add a compatible for the H3
  2021-01-03 10:30 ` Samuel Holland
@ 2021-01-03 10:30   ` Samuel Holland
  -1 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel,
	linux-sunxi, Samuel Holland

The Allwinner H3 SoC contains an R_INTC that is, as far as we know,
compatible with the R_INTC present in other sun8i/sun50i SoCs starting
with the A31. Since the R_INTC hardware is undocumented, introduce a new
compatible for the R_INTC variant in this SoC, in case there turns out
to be some difference.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 .../interrupt-controller/allwinner,sun6i-a31-r-intc.yaml         | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml
index 18805b6555c2..9de1fb2a63d1 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml
@@ -26,6 +26,7 @@ properties:
       - items:
           - enum:
               - allwinner,sun8i-a83t-r-intc
+              - allwinner,sun8i-h3-r-intc
               - allwinner,sun50i-a64-r-intc
               - allwinner,sun50i-h6-r-intc
           - const: allwinner,sun6i-a31-r-intc
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 02/10] dt-bindings: irq: sun6i-r: Add a compatible for the H3
@ 2021-01-03 10:30   ` Samuel Holland
  0 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, Samuel Holland, linux-kernel,
	linux-sunxi, linux-arm-kernel

The Allwinner H3 SoC contains an R_INTC that is, as far as we know,
compatible with the R_INTC present in other sun8i/sun50i SoCs starting
with the A31. Since the R_INTC hardware is undocumented, introduce a new
compatible for the R_INTC variant in this SoC, in case there turns out
to be some difference.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 .../interrupt-controller/allwinner,sun6i-a31-r-intc.yaml         | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml
index 18805b6555c2..9de1fb2a63d1 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml
@@ -26,6 +26,7 @@ properties:
       - items:
           - enum:
               - allwinner,sun8i-a83t-r-intc
+              - allwinner,sun8i-h3-r-intc
               - allwinner,sun50i-a64-r-intc
               - allwinner,sun50i-h6-r-intc
           - const: allwinner,sun6i-a31-r-intc
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 03/10] irqchip/sun6i-r: Use a stacked irqchip driver
  2021-01-03 10:30 ` Samuel Holland
@ 2021-01-03 10:30   ` Samuel Holland
  -1 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel,
	linux-sunxi, Samuel Holland

The R_INTC in the A31 and newer sun8i/sun50i SoCs is more similar to the
original sun4i interrupt controller than the sun7i/sun9i NMI controller.
It is used for two distinct purposes:
 - To control the trigger, latch, and mask for the NMI input pin
 - To provide the interrupt input for the ARISC coprocessor

As this interrupt controller is not documented, information about it
comes from vendor-provided firmware blobs and from experimentation.

Like the original sun4i interrupt controller, it has:
 - A VECTOR_REG at 0x00 (configurable via the BASE_ADDR_REG at 0x04)
 - A NMI_CTRL_REG, PENDING_REG, and ENABLE_REG as used by both the
   sun4i and sunxi-nmi drivers
 - A MASK_REG at 0x50
 - A RESP_REG at 0x60

Differences from the sun4i interrupt controller appear to be:
 - It only has one or two registers of each kind (max 32 or 64 IRQs)
 - Multiplexing logic is added to support additional inputs
 - There is no FIQ-related logic
 - There is no interrupt priority logic

In order to fulfill its two purposes, this hardware block combines four
types of IRQs. First, the NMI pin is routed to the "IRQ 0" input on this
chip, with a trigger type controlled by the NMI_CTRL_REG. The "IRQ 0
pending" output from this chip, if enabled, is then routed to a SPI IRQ
input on the GIC. In other words, bit 0 of IRQ_ENABLE_REG *does* affect
the NMI IRQ seen at the GIC.

The NMI is followed by a contiguous block of 15 "direct" (my name for
them) IRQ inputs that are connected in parallel to both R_INTC and the
GIC. Or in other words, these bits of IRQ_ENABLE_REG *do not* affect the
IRQs seen at the GIC.

Following the direct IRQs are the ARISC's copy of banked IRQs for shared
peripherals. These are not relevant to Linux. The remaining IRQs are
connected to a multiplexer and provide access to the first (up to) 128
SPIs from the ARISC. This range of SPIs overlaps with the direct IRQs.

Finally, the global "IRQ pending" output from R_INTC, after being masked
by MASK_REG and RESP_REG, is connected to the "external interrupt" input
of the ARISC CPU. This path is also irrelevant to Linux.

Because of the 1:1 correspondence between R_INTC and GIC inputs, this is
a perfect scenario for using a stacked irqchip driver. We want to hook
into enabling/disabling IRQs to add more features to the GIC
(specifically to allow masking the NMI and setting its trigger type),
but we don't need to actually handle the IRQ in this driver.

And since R_INTC is in the always-on power domain, and its output is
connected directly in to the power management coprocessor, a stacked
irqchip driver provides a simple way to add wakeup support to this set
of IRQs. That is the next patch; for now, just the NMI is moved over.

To allow access to all multiplexed IRQs, this driver requires a new
binding where the interrupt number matches the GIC interrupt number.
(This moves the NMI number from 0 to 32 or 96, depending on the SoC.)
For simplicity, copy the three-cell GIC binding; this disambiguates
interrupt 0 in the old binding (the NMI) from interrupt 0 in the new
binding (SPI 0) by the number of cells.

This commit mostly reverts commit 173bda53b340 ("irqchip/sunxi-nmi:
Support sun6i-a31-r-intc compatible").

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/arm/mach-sunxi/Kconfig     |   1 +
 arch/arm64/Kconfig.platforms    |   1 +
 drivers/irqchip/Makefile        |   1 +
 drivers/irqchip/irq-sun6i-r.c   | 267 ++++++++++++++++++++++++++++++++
 drivers/irqchip/irq-sunxi-nmi.c |  26 +---
 5 files changed, 273 insertions(+), 23 deletions(-)
 create mode 100644 drivers/irqchip/irq-sun6i-r.c

diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index eeadb1a4dcfe..ef1cc25902b5 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -6,6 +6,7 @@ menuconfig ARCH_SUNXI
 	select CLKSRC_MMIO
 	select GENERIC_IRQ_CHIP
 	select GPIOLIB
+	select IRQ_DOMAIN_HIERARCHY
 	select PINCTRL
 	select PM_OPP
 	select SUN4I_TIMER
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 6eecdef538bd..eec63d2d9d96 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -17,6 +17,7 @@ config ARCH_SUNXI
 	bool "Allwinner sunxi 64-bit SoC Family"
 	select ARCH_HAS_RESET_CONTROLLER
 	select GENERIC_IRQ_CHIP
+	select IRQ_DOMAIN_HIERARCHY
 	select PINCTRL
 	select RESET_CONTROLLER
 	help
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 0ac93bfaec61..95221e74ee99 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_OR1K_PIC)			+= irq-or1k-pic.o
 obj-$(CONFIG_ORION_IRQCHIP)		+= irq-orion.o
 obj-$(CONFIG_OMAP_IRQCHIP)		+= irq-omap-intc.o
 obj-$(CONFIG_ARCH_SUNXI)		+= irq-sun4i.o
+obj-$(CONFIG_ARCH_SUNXI)		+= irq-sun6i-r.o
 obj-$(CONFIG_ARCH_SUNXI)		+= irq-sunxi-nmi.o
 obj-$(CONFIG_ARCH_SPEAR3XX)		+= spear-shirq.o
 obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
diff --git a/drivers/irqchip/irq-sun6i-r.c b/drivers/irqchip/irq-sun6i-r.c
new file mode 100644
index 000000000000..7490ade7b254
--- /dev/null
+++ b/drivers/irqchip/irq-sun6i-r.c
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// R_INTC driver for Allwinner A31 and newer SoCs
+//
+
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/*
+ * The R_INTC manages between 32 and 64 IRQs, divided into four groups. Example
+ * bit numbers are for the original variant in the A31:
+ *
+ *   Bit      0: The "External NMI" input, connected in series to a GIC SPI.
+ *   Bits  1-15: "Direct" IRQs for ARISC peripherals, connected in parallel to
+ *               the GIC and mapped 1:1 to SPIs numerically following the NMI.
+ *   Bits 16-18: "Banked" IRQs for peripherals that have separate interfaces
+ *               for the ARM CPUs and ARISC. These do not map to any GIC SPI.
+ *   Bits 19-31: "Muxed" IRQs, each corresponding to a group of up to 8 SPIs.
+ *               Later variants added a second PENDING and ENABLE register to
+ *               make use of all 128 mux inputs (16 IRQ lines).
+ *
+ * Since the direct IRQs are inside the muxed IRQ range, they do not increase
+ * the number of HWIRQs needed.
+ */
+#define SUN6I_NR_IRQS			64
+#define SUN6I_NR_DIRECT_IRQS		16
+#define SUN6I_NR_MUX_INPUTS		128
+#define SUN6I_NR_HWIRQS			SUN6I_NR_MUX_INPUTS
+
+#define SUN6I_NMI_CTRL			(0x0c)
+#define SUN6I_IRQ_PENDING(n)		(0x10 + 4 * (n))
+#define SUN6I_IRQ_ENABLE(n)		(0x40 + 4 * (n))
+#define SUN6I_MUX_ENABLE(n)		(0xc0 + 4 * (n))
+
+#define SUN6I_NMI_IRQ_BIT		BIT(0)
+
+static void __iomem *base;
+static irq_hw_number_t nmi_hwirq;
+static u32 nmi_type;
+
+static struct irq_chip sun6i_r_intc_edge_chip;
+static struct irq_chip sun6i_r_intc_level_chip;
+
+static void sun6i_r_intc_nmi_ack(void)
+{
+	/*
+	 * The NMI channel has a latch separate from its trigger type.
+	 * This latch must be cleared to clear the signal to the GIC.
+	 */
+	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_PENDING(0));
+}
+
+static void sun6i_r_intc_irq_mask(struct irq_data *data)
+{
+	if (data->hwirq == nmi_hwirq)
+		sun6i_r_intc_nmi_ack();
+
+	irq_chip_mask_parent(data);
+}
+
+static void sun6i_r_intc_irq_unmask(struct irq_data *data)
+{
+	if (data->hwirq == nmi_hwirq)
+		sun6i_r_intc_nmi_ack();
+
+	irq_chip_unmask_parent(data);
+}
+
+static int sun6i_r_intc_irq_set_type(struct irq_data *data, unsigned int type)
+{
+	/*
+	 * The GIC input labeled "External NMI" connects to bit 0 of the R_INTC
+	 * PENDING register, not to the pin directly. So the trigger type of the
+	 * GIC input does not depend on the trigger type of the NMI pin itself.
+	 *
+	 * Only the NMI channel is routed through this interrupt controller on
+	 * its way to the GIC. Other IRQs are routed to the GIC and R_INTC in
+	 * parallel; they must have a trigger type appropriate for the GIC.
+	 */
+	if (data->hwirq == nmi_hwirq) {
+		struct irq_chip *chip;
+		u32 nmi_src_type;
+
+		switch (type) {
+		case IRQ_TYPE_LEVEL_LOW:
+			chip = &sun6i_r_intc_level_chip;
+			nmi_src_type = 0;
+			break;
+		case IRQ_TYPE_EDGE_FALLING:
+			chip = &sun6i_r_intc_edge_chip;
+			nmi_src_type = 1;
+			break;
+		case IRQ_TYPE_LEVEL_HIGH:
+			chip = &sun6i_r_intc_level_chip;
+			nmi_src_type = 2;
+			break;
+		case IRQ_TYPE_EDGE_RISING:
+			chip = &sun6i_r_intc_edge_chip;
+			nmi_src_type = 3;
+			break;
+		default:
+			pr_err("%pOF: invalid trigger type %d for IRQ %d\n",
+			       irq_domain_get_of_node(data->domain), type,
+			       data->irq);
+			return -EBADR;
+		}
+
+		irq_set_chip_handler_name_locked(data, chip,
+						 handle_fasteoi_irq, NULL);
+
+		writel_relaxed(nmi_src_type, base + SUN6I_NMI_CTRL);
+
+		/*
+		 * Use the trigger type from the OF node for the NMI's
+		 * R_INTC to GIC connection.
+		 */
+		type = nmi_type;
+	}
+
+	return irq_chip_set_type_parent(data, type);
+}
+
+static struct irq_chip sun6i_r_intc_edge_chip = {
+	.name			= "sun6i-r-intc",
+	.irq_mask		= sun6i_r_intc_irq_mask,
+	.irq_unmask		= irq_chip_unmask_parent,
+	.irq_eoi		= irq_chip_eoi_parent,
+	.irq_set_affinity	= irq_chip_set_affinity_parent,
+	.irq_set_type		= sun6i_r_intc_irq_set_type,
+	.irq_get_irqchip_state	= irq_chip_get_parent_state,
+	.irq_set_irqchip_state	= irq_chip_set_parent_state,
+	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
+	.flags			= IRQCHIP_SET_TYPE_MASKED,
+};
+
+static struct irq_chip sun6i_r_intc_level_chip = {
+	.name			= "sun6i-r-intc",
+	.irq_mask		= irq_chip_mask_parent,
+	.irq_unmask		= sun6i_r_intc_irq_unmask,
+	.irq_eoi		= irq_chip_eoi_parent,
+	.irq_set_affinity	= irq_chip_set_affinity_parent,
+	.irq_set_type		= sun6i_r_intc_irq_set_type,
+	.irq_get_irqchip_state	= irq_chip_get_parent_state,
+	.irq_set_irqchip_state	= irq_chip_set_parent_state,
+	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
+	.flags			= IRQCHIP_SET_TYPE_MASKED,
+};
+
+static int sun6i_r_intc_domain_translate(struct irq_domain *domain,
+					 struct irq_fwspec *fwspec,
+					 unsigned long *hwirq,
+					 unsigned int *type)
+{
+	/* Accept the old two-cell binding for the NMI only. */
+	if (fwspec->param_count == 2 && fwspec->param[0] == 0) {
+		*hwirq = nmi_hwirq;
+		*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
+		return 0;
+	}
+
+	/* Otherwise this binding should match the GIC SPI binding. */
+	if (fwspec->param_count < 3)
+		return -EINVAL;
+	if (fwspec->param[0] != GIC_SPI)
+		return -EINVAL;
+
+	*hwirq = fwspec->param[1];
+	*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
+
+	return 0;
+}
+
+static int sun6i_r_intc_domain_alloc(struct irq_domain *domain,
+				     unsigned int virq,
+				     unsigned int nr_irqs, void *arg)
+{
+	struct irq_fwspec *fwspec = arg;
+	struct irq_fwspec gic_fwspec;
+	unsigned long hwirq;
+	unsigned int type;
+	int i, ret;
+
+	ret = sun6i_r_intc_domain_translate(domain, fwspec, &hwirq, &type);
+	if (ret)
+		return ret;
+	if (hwirq + nr_irqs > SUN6I_NR_HWIRQS)
+		return -EINVAL;
+
+	/* Construct a GIC-compatible fwspec from this fwspec. */
+	gic_fwspec = (struct irq_fwspec) {
+		.fwnode      = domain->parent->fwnode,
+		.param_count = 3,
+		.param       = { GIC_SPI, hwirq, type },
+	};
+
+	for (i = 0; i < nr_irqs; ++i)
+		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+					      &sun6i_r_intc_level_chip, NULL);
+
+	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_fwspec);
+}
+
+static const struct irq_domain_ops sun6i_r_intc_domain_ops = {
+	.translate	= sun6i_r_intc_domain_translate,
+	.alloc		= sun6i_r_intc_domain_alloc,
+	.free		= irq_domain_free_irqs_common,
+};
+
+static void sun6i_r_intc_resume(void)
+{
+	int i;
+
+	/* Only the NMI is relevant during normal operation. */
+	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_ENABLE(0));
+	for (i = 1; i < BITS_TO_U32(SUN6I_NR_IRQS); ++i)
+		writel_relaxed(0, base + SUN6I_IRQ_ENABLE(i));
+}
+
+static int __init sun6i_r_intc_init(struct device_node *node,
+				    struct device_node *parent)
+{
+	struct irq_domain *domain, *parent_domain;
+	struct of_phandle_args parent_irq;
+	int ret;
+
+	/* Extract the NMI's R_INTC to GIC mapping from the OF node. */
+	ret = of_irq_parse_one(node, 0, &parent_irq);
+	if (ret)
+		return ret;
+	if (parent_irq.args_count < 3 || parent_irq.args[0] != GIC_SPI)
+		return -EINVAL;
+	nmi_hwirq = parent_irq.args[1];
+	nmi_type = parent_irq.args[2];
+
+	parent_domain = irq_find_host(parent);
+	if (!parent_domain) {
+		pr_err("%pOF: Failed to obtain parent domain\n", node);
+		return -ENXIO;
+	}
+
+	base = of_io_request_and_map(node, 0, NULL);
+	if (IS_ERR(base)) {
+		pr_err("%pOF: Failed to map MMIO region\n", node);
+		return PTR_ERR(base);
+	}
+
+	sun6i_r_intc_nmi_ack();
+	sun6i_r_intc_resume();
+
+	domain = irq_domain_add_hierarchy(parent_domain, 0,
+					  SUN6I_NR_HWIRQS, node,
+					  &sun6i_r_intc_domain_ops, NULL);
+	if (!domain) {
+		pr_err("%pOF: Failed to allocate domain\n", node);
+		iounmap(base);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+IRQCHIP_DECLARE(sun6i_r_intc, "allwinner,sun6i-a31-r-intc", sun6i_r_intc_init);
diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c
index a412b5d5d0fa..9f2bd0c5d289 100644
--- a/drivers/irqchip/irq-sunxi-nmi.c
+++ b/drivers/irqchip/irq-sunxi-nmi.c
@@ -27,18 +27,12 @@
 
 #define SUNXI_NMI_IRQ_BIT	BIT(0)
 
-#define SUN6I_R_INTC_CTRL	0x0c
-#define SUN6I_R_INTC_PENDING	0x10
-#define SUN6I_R_INTC_ENABLE	0x40
-
 /*
  * For deprecated sun6i-a31-sc-nmi compatible.
- * Registers are offset by 0x0c.
  */
-#define SUN6I_R_INTC_NMI_OFFSET	0x0c
-#define SUN6I_NMI_CTRL		(SUN6I_R_INTC_CTRL - SUN6I_R_INTC_NMI_OFFSET)
-#define SUN6I_NMI_PENDING	(SUN6I_R_INTC_PENDING - SUN6I_R_INTC_NMI_OFFSET)
-#define SUN6I_NMI_ENABLE	(SUN6I_R_INTC_ENABLE - SUN6I_R_INTC_NMI_OFFSET)
+#define SUN6I_NMI_CTRL		0x00
+#define SUN6I_NMI_PENDING	0x04
+#define SUN6I_NMI_ENABLE	0x34
 
 #define SUN7I_NMI_CTRL		0x00
 #define SUN7I_NMI_PENDING	0x04
@@ -61,12 +55,6 @@ struct sunxi_sc_nmi_reg_offs {
 	u32 enable;
 };
 
-static const struct sunxi_sc_nmi_reg_offs sun6i_r_intc_reg_offs __initconst = {
-	.ctrl	= SUN6I_R_INTC_CTRL,
-	.pend	= SUN6I_R_INTC_PENDING,
-	.enable	= SUN6I_R_INTC_ENABLE,
-};
-
 static const struct sunxi_sc_nmi_reg_offs sun6i_reg_offs __initconst = {
 	.ctrl	= SUN6I_NMI_CTRL,
 	.pend	= SUN6I_NMI_PENDING,
@@ -232,14 +220,6 @@ static int __init sunxi_sc_nmi_irq_init(struct device_node *node,
 	return ret;
 }
 
-static int __init sun6i_r_intc_irq_init(struct device_node *node,
-					struct device_node *parent)
-{
-	return sunxi_sc_nmi_irq_init(node, &sun6i_r_intc_reg_offs);
-}
-IRQCHIP_DECLARE(sun6i_r_intc, "allwinner,sun6i-a31-r-intc",
-		sun6i_r_intc_irq_init);
-
 static int __init sun6i_sc_nmi_irq_init(struct device_node *node,
 					struct device_node *parent)
 {
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 03/10] irqchip/sun6i-r: Use a stacked irqchip driver
@ 2021-01-03 10:30   ` Samuel Holland
  0 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, Samuel Holland, linux-kernel,
	linux-sunxi, linux-arm-kernel

The R_INTC in the A31 and newer sun8i/sun50i SoCs is more similar to the
original sun4i interrupt controller than the sun7i/sun9i NMI controller.
It is used for two distinct purposes:
 - To control the trigger, latch, and mask for the NMI input pin
 - To provide the interrupt input for the ARISC coprocessor

As this interrupt controller is not documented, information about it
comes from vendor-provided firmware blobs and from experimentation.

Like the original sun4i interrupt controller, it has:
 - A VECTOR_REG at 0x00 (configurable via the BASE_ADDR_REG at 0x04)
 - A NMI_CTRL_REG, PENDING_REG, and ENABLE_REG as used by both the
   sun4i and sunxi-nmi drivers
 - A MASK_REG at 0x50
 - A RESP_REG at 0x60

Differences from the sun4i interrupt controller appear to be:
 - It only has one or two registers of each kind (max 32 or 64 IRQs)
 - Multiplexing logic is added to support additional inputs
 - There is no FIQ-related logic
 - There is no interrupt priority logic

In order to fulfill its two purposes, this hardware block combines four
types of IRQs. First, the NMI pin is routed to the "IRQ 0" input on this
chip, with a trigger type controlled by the NMI_CTRL_REG. The "IRQ 0
pending" output from this chip, if enabled, is then routed to a SPI IRQ
input on the GIC. In other words, bit 0 of IRQ_ENABLE_REG *does* affect
the NMI IRQ seen at the GIC.

The NMI is followed by a contiguous block of 15 "direct" (my name for
them) IRQ inputs that are connected in parallel to both R_INTC and the
GIC. Or in other words, these bits of IRQ_ENABLE_REG *do not* affect the
IRQs seen at the GIC.

Following the direct IRQs are the ARISC's copy of banked IRQs for shared
peripherals. These are not relevant to Linux. The remaining IRQs are
connected to a multiplexer and provide access to the first (up to) 128
SPIs from the ARISC. This range of SPIs overlaps with the direct IRQs.

Finally, the global "IRQ pending" output from R_INTC, after being masked
by MASK_REG and RESP_REG, is connected to the "external interrupt" input
of the ARISC CPU. This path is also irrelevant to Linux.

Because of the 1:1 correspondence between R_INTC and GIC inputs, this is
a perfect scenario for using a stacked irqchip driver. We want to hook
into enabling/disabling IRQs to add more features to the GIC
(specifically to allow masking the NMI and setting its trigger type),
but we don't need to actually handle the IRQ in this driver.

And since R_INTC is in the always-on power domain, and its output is
connected directly in to the power management coprocessor, a stacked
irqchip driver provides a simple way to add wakeup support to this set
of IRQs. That is the next patch; for now, just the NMI is moved over.

To allow access to all multiplexed IRQs, this driver requires a new
binding where the interrupt number matches the GIC interrupt number.
(This moves the NMI number from 0 to 32 or 96, depending on the SoC.)
For simplicity, copy the three-cell GIC binding; this disambiguates
interrupt 0 in the old binding (the NMI) from interrupt 0 in the new
binding (SPI 0) by the number of cells.

This commit mostly reverts commit 173bda53b340 ("irqchip/sunxi-nmi:
Support sun6i-a31-r-intc compatible").

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/arm/mach-sunxi/Kconfig     |   1 +
 arch/arm64/Kconfig.platforms    |   1 +
 drivers/irqchip/Makefile        |   1 +
 drivers/irqchip/irq-sun6i-r.c   | 267 ++++++++++++++++++++++++++++++++
 drivers/irqchip/irq-sunxi-nmi.c |  26 +---
 5 files changed, 273 insertions(+), 23 deletions(-)
 create mode 100644 drivers/irqchip/irq-sun6i-r.c

diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index eeadb1a4dcfe..ef1cc25902b5 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -6,6 +6,7 @@ menuconfig ARCH_SUNXI
 	select CLKSRC_MMIO
 	select GENERIC_IRQ_CHIP
 	select GPIOLIB
+	select IRQ_DOMAIN_HIERARCHY
 	select PINCTRL
 	select PM_OPP
 	select SUN4I_TIMER
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 6eecdef538bd..eec63d2d9d96 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -17,6 +17,7 @@ config ARCH_SUNXI
 	bool "Allwinner sunxi 64-bit SoC Family"
 	select ARCH_HAS_RESET_CONTROLLER
 	select GENERIC_IRQ_CHIP
+	select IRQ_DOMAIN_HIERARCHY
 	select PINCTRL
 	select RESET_CONTROLLER
 	help
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 0ac93bfaec61..95221e74ee99 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_OR1K_PIC)			+= irq-or1k-pic.o
 obj-$(CONFIG_ORION_IRQCHIP)		+= irq-orion.o
 obj-$(CONFIG_OMAP_IRQCHIP)		+= irq-omap-intc.o
 obj-$(CONFIG_ARCH_SUNXI)		+= irq-sun4i.o
+obj-$(CONFIG_ARCH_SUNXI)		+= irq-sun6i-r.o
 obj-$(CONFIG_ARCH_SUNXI)		+= irq-sunxi-nmi.o
 obj-$(CONFIG_ARCH_SPEAR3XX)		+= spear-shirq.o
 obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
diff --git a/drivers/irqchip/irq-sun6i-r.c b/drivers/irqchip/irq-sun6i-r.c
new file mode 100644
index 000000000000..7490ade7b254
--- /dev/null
+++ b/drivers/irqchip/irq-sun6i-r.c
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// R_INTC driver for Allwinner A31 and newer SoCs
+//
+
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/*
+ * The R_INTC manages between 32 and 64 IRQs, divided into four groups. Example
+ * bit numbers are for the original variant in the A31:
+ *
+ *   Bit      0: The "External NMI" input, connected in series to a GIC SPI.
+ *   Bits  1-15: "Direct" IRQs for ARISC peripherals, connected in parallel to
+ *               the GIC and mapped 1:1 to SPIs numerically following the NMI.
+ *   Bits 16-18: "Banked" IRQs for peripherals that have separate interfaces
+ *               for the ARM CPUs and ARISC. These do not map to any GIC SPI.
+ *   Bits 19-31: "Muxed" IRQs, each corresponding to a group of up to 8 SPIs.
+ *               Later variants added a second PENDING and ENABLE register to
+ *               make use of all 128 mux inputs (16 IRQ lines).
+ *
+ * Since the direct IRQs are inside the muxed IRQ range, they do not increase
+ * the number of HWIRQs needed.
+ */
+#define SUN6I_NR_IRQS			64
+#define SUN6I_NR_DIRECT_IRQS		16
+#define SUN6I_NR_MUX_INPUTS		128
+#define SUN6I_NR_HWIRQS			SUN6I_NR_MUX_INPUTS
+
+#define SUN6I_NMI_CTRL			(0x0c)
+#define SUN6I_IRQ_PENDING(n)		(0x10 + 4 * (n))
+#define SUN6I_IRQ_ENABLE(n)		(0x40 + 4 * (n))
+#define SUN6I_MUX_ENABLE(n)		(0xc0 + 4 * (n))
+
+#define SUN6I_NMI_IRQ_BIT		BIT(0)
+
+static void __iomem *base;
+static irq_hw_number_t nmi_hwirq;
+static u32 nmi_type;
+
+static struct irq_chip sun6i_r_intc_edge_chip;
+static struct irq_chip sun6i_r_intc_level_chip;
+
+static void sun6i_r_intc_nmi_ack(void)
+{
+	/*
+	 * The NMI channel has a latch separate from its trigger type.
+	 * This latch must be cleared to clear the signal to the GIC.
+	 */
+	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_PENDING(0));
+}
+
+static void sun6i_r_intc_irq_mask(struct irq_data *data)
+{
+	if (data->hwirq == nmi_hwirq)
+		sun6i_r_intc_nmi_ack();
+
+	irq_chip_mask_parent(data);
+}
+
+static void sun6i_r_intc_irq_unmask(struct irq_data *data)
+{
+	if (data->hwirq == nmi_hwirq)
+		sun6i_r_intc_nmi_ack();
+
+	irq_chip_unmask_parent(data);
+}
+
+static int sun6i_r_intc_irq_set_type(struct irq_data *data, unsigned int type)
+{
+	/*
+	 * The GIC input labeled "External NMI" connects to bit 0 of the R_INTC
+	 * PENDING register, not to the pin directly. So the trigger type of the
+	 * GIC input does not depend on the trigger type of the NMI pin itself.
+	 *
+	 * Only the NMI channel is routed through this interrupt controller on
+	 * its way to the GIC. Other IRQs are routed to the GIC and R_INTC in
+	 * parallel; they must have a trigger type appropriate for the GIC.
+	 */
+	if (data->hwirq == nmi_hwirq) {
+		struct irq_chip *chip;
+		u32 nmi_src_type;
+
+		switch (type) {
+		case IRQ_TYPE_LEVEL_LOW:
+			chip = &sun6i_r_intc_level_chip;
+			nmi_src_type = 0;
+			break;
+		case IRQ_TYPE_EDGE_FALLING:
+			chip = &sun6i_r_intc_edge_chip;
+			nmi_src_type = 1;
+			break;
+		case IRQ_TYPE_LEVEL_HIGH:
+			chip = &sun6i_r_intc_level_chip;
+			nmi_src_type = 2;
+			break;
+		case IRQ_TYPE_EDGE_RISING:
+			chip = &sun6i_r_intc_edge_chip;
+			nmi_src_type = 3;
+			break;
+		default:
+			pr_err("%pOF: invalid trigger type %d for IRQ %d\n",
+			       irq_domain_get_of_node(data->domain), type,
+			       data->irq);
+			return -EBADR;
+		}
+
+		irq_set_chip_handler_name_locked(data, chip,
+						 handle_fasteoi_irq, NULL);
+
+		writel_relaxed(nmi_src_type, base + SUN6I_NMI_CTRL);
+
+		/*
+		 * Use the trigger type from the OF node for the NMI's
+		 * R_INTC to GIC connection.
+		 */
+		type = nmi_type;
+	}
+
+	return irq_chip_set_type_parent(data, type);
+}
+
+static struct irq_chip sun6i_r_intc_edge_chip = {
+	.name			= "sun6i-r-intc",
+	.irq_mask		= sun6i_r_intc_irq_mask,
+	.irq_unmask		= irq_chip_unmask_parent,
+	.irq_eoi		= irq_chip_eoi_parent,
+	.irq_set_affinity	= irq_chip_set_affinity_parent,
+	.irq_set_type		= sun6i_r_intc_irq_set_type,
+	.irq_get_irqchip_state	= irq_chip_get_parent_state,
+	.irq_set_irqchip_state	= irq_chip_set_parent_state,
+	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
+	.flags			= IRQCHIP_SET_TYPE_MASKED,
+};
+
+static struct irq_chip sun6i_r_intc_level_chip = {
+	.name			= "sun6i-r-intc",
+	.irq_mask		= irq_chip_mask_parent,
+	.irq_unmask		= sun6i_r_intc_irq_unmask,
+	.irq_eoi		= irq_chip_eoi_parent,
+	.irq_set_affinity	= irq_chip_set_affinity_parent,
+	.irq_set_type		= sun6i_r_intc_irq_set_type,
+	.irq_get_irqchip_state	= irq_chip_get_parent_state,
+	.irq_set_irqchip_state	= irq_chip_set_parent_state,
+	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
+	.flags			= IRQCHIP_SET_TYPE_MASKED,
+};
+
+static int sun6i_r_intc_domain_translate(struct irq_domain *domain,
+					 struct irq_fwspec *fwspec,
+					 unsigned long *hwirq,
+					 unsigned int *type)
+{
+	/* Accept the old two-cell binding for the NMI only. */
+	if (fwspec->param_count == 2 && fwspec->param[0] == 0) {
+		*hwirq = nmi_hwirq;
+		*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
+		return 0;
+	}
+
+	/* Otherwise this binding should match the GIC SPI binding. */
+	if (fwspec->param_count < 3)
+		return -EINVAL;
+	if (fwspec->param[0] != GIC_SPI)
+		return -EINVAL;
+
+	*hwirq = fwspec->param[1];
+	*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
+
+	return 0;
+}
+
+static int sun6i_r_intc_domain_alloc(struct irq_domain *domain,
+				     unsigned int virq,
+				     unsigned int nr_irqs, void *arg)
+{
+	struct irq_fwspec *fwspec = arg;
+	struct irq_fwspec gic_fwspec;
+	unsigned long hwirq;
+	unsigned int type;
+	int i, ret;
+
+	ret = sun6i_r_intc_domain_translate(domain, fwspec, &hwirq, &type);
+	if (ret)
+		return ret;
+	if (hwirq + nr_irqs > SUN6I_NR_HWIRQS)
+		return -EINVAL;
+
+	/* Construct a GIC-compatible fwspec from this fwspec. */
+	gic_fwspec = (struct irq_fwspec) {
+		.fwnode      = domain->parent->fwnode,
+		.param_count = 3,
+		.param       = { GIC_SPI, hwirq, type },
+	};
+
+	for (i = 0; i < nr_irqs; ++i)
+		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+					      &sun6i_r_intc_level_chip, NULL);
+
+	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_fwspec);
+}
+
+static const struct irq_domain_ops sun6i_r_intc_domain_ops = {
+	.translate	= sun6i_r_intc_domain_translate,
+	.alloc		= sun6i_r_intc_domain_alloc,
+	.free		= irq_domain_free_irqs_common,
+};
+
+static void sun6i_r_intc_resume(void)
+{
+	int i;
+
+	/* Only the NMI is relevant during normal operation. */
+	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_ENABLE(0));
+	for (i = 1; i < BITS_TO_U32(SUN6I_NR_IRQS); ++i)
+		writel_relaxed(0, base + SUN6I_IRQ_ENABLE(i));
+}
+
+static int __init sun6i_r_intc_init(struct device_node *node,
+				    struct device_node *parent)
+{
+	struct irq_domain *domain, *parent_domain;
+	struct of_phandle_args parent_irq;
+	int ret;
+
+	/* Extract the NMI's R_INTC to GIC mapping from the OF node. */
+	ret = of_irq_parse_one(node, 0, &parent_irq);
+	if (ret)
+		return ret;
+	if (parent_irq.args_count < 3 || parent_irq.args[0] != GIC_SPI)
+		return -EINVAL;
+	nmi_hwirq = parent_irq.args[1];
+	nmi_type = parent_irq.args[2];
+
+	parent_domain = irq_find_host(parent);
+	if (!parent_domain) {
+		pr_err("%pOF: Failed to obtain parent domain\n", node);
+		return -ENXIO;
+	}
+
+	base = of_io_request_and_map(node, 0, NULL);
+	if (IS_ERR(base)) {
+		pr_err("%pOF: Failed to map MMIO region\n", node);
+		return PTR_ERR(base);
+	}
+
+	sun6i_r_intc_nmi_ack();
+	sun6i_r_intc_resume();
+
+	domain = irq_domain_add_hierarchy(parent_domain, 0,
+					  SUN6I_NR_HWIRQS, node,
+					  &sun6i_r_intc_domain_ops, NULL);
+	if (!domain) {
+		pr_err("%pOF: Failed to allocate domain\n", node);
+		iounmap(base);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+IRQCHIP_DECLARE(sun6i_r_intc, "allwinner,sun6i-a31-r-intc", sun6i_r_intc_init);
diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c
index a412b5d5d0fa..9f2bd0c5d289 100644
--- a/drivers/irqchip/irq-sunxi-nmi.c
+++ b/drivers/irqchip/irq-sunxi-nmi.c
@@ -27,18 +27,12 @@
 
 #define SUNXI_NMI_IRQ_BIT	BIT(0)
 
-#define SUN6I_R_INTC_CTRL	0x0c
-#define SUN6I_R_INTC_PENDING	0x10
-#define SUN6I_R_INTC_ENABLE	0x40
-
 /*
  * For deprecated sun6i-a31-sc-nmi compatible.
- * Registers are offset by 0x0c.
  */
-#define SUN6I_R_INTC_NMI_OFFSET	0x0c
-#define SUN6I_NMI_CTRL		(SUN6I_R_INTC_CTRL - SUN6I_R_INTC_NMI_OFFSET)
-#define SUN6I_NMI_PENDING	(SUN6I_R_INTC_PENDING - SUN6I_R_INTC_NMI_OFFSET)
-#define SUN6I_NMI_ENABLE	(SUN6I_R_INTC_ENABLE - SUN6I_R_INTC_NMI_OFFSET)
+#define SUN6I_NMI_CTRL		0x00
+#define SUN6I_NMI_PENDING	0x04
+#define SUN6I_NMI_ENABLE	0x34
 
 #define SUN7I_NMI_CTRL		0x00
 #define SUN7I_NMI_PENDING	0x04
@@ -61,12 +55,6 @@ struct sunxi_sc_nmi_reg_offs {
 	u32 enable;
 };
 
-static const struct sunxi_sc_nmi_reg_offs sun6i_r_intc_reg_offs __initconst = {
-	.ctrl	= SUN6I_R_INTC_CTRL,
-	.pend	= SUN6I_R_INTC_PENDING,
-	.enable	= SUN6I_R_INTC_ENABLE,
-};
-
 static const struct sunxi_sc_nmi_reg_offs sun6i_reg_offs __initconst = {
 	.ctrl	= SUN6I_NMI_CTRL,
 	.pend	= SUN6I_NMI_PENDING,
@@ -232,14 +220,6 @@ static int __init sunxi_sc_nmi_irq_init(struct device_node *node,
 	return ret;
 }
 
-static int __init sun6i_r_intc_irq_init(struct device_node *node,
-					struct device_node *parent)
-{
-	return sunxi_sc_nmi_irq_init(node, &sun6i_r_intc_reg_offs);
-}
-IRQCHIP_DECLARE(sun6i_r_intc, "allwinner,sun6i-a31-r-intc",
-		sun6i_r_intc_irq_init);
-
 static int __init sun6i_sc_nmi_irq_init(struct device_node *node,
 					struct device_node *parent)
 {
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 04/10] irqchip/sun6i-r: Add wakeup support
  2021-01-03 10:30 ` Samuel Holland
@ 2021-01-03 10:30   ` Samuel Holland
  -1 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel,
	linux-sunxi, Samuel Holland

Maintain bitmaps of wake-enabled IRQs and mux inputs, and program them
to the hardware during the syscore phase of suspend and shutdown. Then
restore the original set of enabled IRQs (only the NMI) during resume.

This serves two purposes. First, it lets power management firmware
running on the ARISC coprocessor know which wakeup sources Linux wants
to have enabled. That way, it can avoid turning them off when it shuts
down the remainder of the clock tree. Second, it preconfigures the
coprocessor's interrupt controller, so the firmware's wakeup logic
is as simple as waiting for an interrupt to arrive.

The suspend/resume logic is not conditional on PM_SLEEP because it is
identical to the init/shutdown logic. Wake IRQs may be enabled during
shutdown to allow powering the board back on. As an example, see
commit a5c5e50cce9d ("Input: gpio-keys - add shutdown callback").

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 drivers/irqchip/irq-sun6i-r.c | 90 ++++++++++++++++++++++++++++++++++-
 1 file changed, 88 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-sun6i-r.c b/drivers/irqchip/irq-sun6i-r.c
index 7490ade7b254..70be0fd228c2 100644
--- a/drivers/irqchip/irq-sun6i-r.c
+++ b/drivers/irqchip/irq-sun6i-r.c
@@ -3,12 +3,14 @@
 // R_INTC driver for Allwinner A31 and newer SoCs
 //
 
+#include <linux/bitmap.h>
 #include <linux/irq.h>
 #include <linux/irqchip.h>
 #include <linux/irqdomain.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <linux/syscore_ops.h>
 
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
@@ -40,9 +42,18 @@
 
 #define SUN6I_NMI_IRQ_BIT		BIT(0)
 
+struct sun6i_r_intc_variant {
+	u32	first_mux_irq;
+	u32	nr_mux_irqs;
+	u32	mux_valid[BITS_TO_U32(SUN6I_NR_MUX_INPUTS)];
+};
+
 static void __iomem *base;
 static irq_hw_number_t nmi_hwirq;
 static u32 nmi_type;
+static DECLARE_BITMAP(wake_irq_enabled, SUN6I_NR_IRQS);
+static DECLARE_BITMAP(wake_mux_enabled, SUN6I_NR_MUX_INPUTS);
+static DECLARE_BITMAP(wake_mux_valid, SUN6I_NR_MUX_INPUTS);
 
 static struct irq_chip sun6i_r_intc_edge_chip;
 static struct irq_chip sun6i_r_intc_level_chip;
@@ -126,6 +137,21 @@ static int sun6i_r_intc_irq_set_type(struct irq_data *data, unsigned int type)
 	return irq_chip_set_type_parent(data, type);
 }
 
+static int sun6i_r_intc_irq_set_wake(struct irq_data *data, unsigned int on)
+{
+	unsigned long offset_from_nmi = data->hwirq - nmi_hwirq;
+
+	if (offset_from_nmi < SUN6I_NR_DIRECT_IRQS)
+		assign_bit(offset_from_nmi, wake_irq_enabled, on);
+	else if (test_bit(data->hwirq, wake_mux_valid))
+		assign_bit(data->hwirq, wake_mux_enabled, on);
+	else
+		/* Not wakeup capable. */
+		return -EPERM;
+
+	return 0;
+}
+
 static struct irq_chip sun6i_r_intc_edge_chip = {
 	.name			= "sun6i-r-intc",
 	.irq_mask		= sun6i_r_intc_irq_mask,
@@ -135,6 +161,7 @@ static struct irq_chip sun6i_r_intc_edge_chip = {
 	.irq_set_type		= sun6i_r_intc_irq_set_type,
 	.irq_get_irqchip_state	= irq_chip_get_parent_state,
 	.irq_set_irqchip_state	= irq_chip_set_parent_state,
+	.irq_set_wake		= sun6i_r_intc_irq_set_wake,
 	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
 	.flags			= IRQCHIP_SET_TYPE_MASKED,
 };
@@ -148,6 +175,7 @@ static struct irq_chip sun6i_r_intc_level_chip = {
 	.irq_set_type		= sun6i_r_intc_irq_set_type,
 	.irq_get_irqchip_state	= irq_chip_get_parent_state,
 	.irq_set_irqchip_state	= irq_chip_set_parent_state,
+	.irq_set_wake		= sun6i_r_intc_irq_set_wake,
 	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
 	.flags			= IRQCHIP_SET_TYPE_MASKED,
 };
@@ -212,6 +240,22 @@ static const struct irq_domain_ops sun6i_r_intc_domain_ops = {
 	.free		= irq_domain_free_irqs_common,
 };
 
+static int sun6i_r_intc_suspend(void)
+{
+	u32 buf[BITS_TO_U32(max(SUN6I_NR_IRQS, SUN6I_NR_MUX_INPUTS))];
+	int i;
+
+	/* Wake IRQs are enabled during system sleep and shutdown. */
+	bitmap_to_arr32(buf, wake_irq_enabled, SUN6I_NR_IRQS);
+	for (i = 0; i < BITS_TO_U32(SUN6I_NR_IRQS); ++i)
+		writel_relaxed(buf[i], base + SUN6I_IRQ_ENABLE(i));
+	bitmap_to_arr32(buf, wake_mux_enabled, SUN6I_NR_MUX_INPUTS);
+	for (i = 0; i < BITS_TO_U32(SUN6I_NR_MUX_INPUTS); ++i)
+		writel_relaxed(buf[i], base + SUN6I_MUX_ENABLE(i));
+
+	return 0;
+}
+
 static void sun6i_r_intc_resume(void)
 {
 	int i;
@@ -222,8 +266,20 @@ static void sun6i_r_intc_resume(void)
 		writel_relaxed(0, base + SUN6I_IRQ_ENABLE(i));
 }
 
+static void sun6i_r_intc_shutdown(void)
+{
+	sun6i_r_intc_suspend();
+}
+
+static struct syscore_ops sun6i_r_intc_syscore_ops = {
+	.suspend	= sun6i_r_intc_suspend,
+	.resume		= sun6i_r_intc_resume,
+	.shutdown	= sun6i_r_intc_shutdown,
+};
+
 static int __init sun6i_r_intc_init(struct device_node *node,
-				    struct device_node *parent)
+				    struct device_node *parent,
+				    const struct sun6i_r_intc_variant *v)
 {
 	struct irq_domain *domain, *parent_domain;
 	struct of_phandle_args parent_irq;
@@ -253,6 +309,9 @@ static int __init sun6i_r_intc_init(struct device_node *node,
 	sun6i_r_intc_nmi_ack();
 	sun6i_r_intc_resume();
 
+	bitmap_set(wake_irq_enabled, v->first_mux_irq, v->nr_mux_irqs);
+	bitmap_from_arr32(wake_mux_valid, v->mux_valid, SUN6I_NR_MUX_INPUTS);
+
 	domain = irq_domain_add_hierarchy(parent_domain, 0,
 					  SUN6I_NR_HWIRQS, node,
 					  &sun6i_r_intc_domain_ops, NULL);
@@ -262,6 +321,33 @@ static int __init sun6i_r_intc_init(struct device_node *node,
 		return -ENOMEM;
 	}
 
+	register_syscore_ops(&sun6i_r_intc_syscore_ops);
+
 	return 0;
 }
-IRQCHIP_DECLARE(sun6i_r_intc, "allwinner,sun6i-a31-r-intc", sun6i_r_intc_init);
+
+static const struct sun6i_r_intc_variant sun6i_a31_r_intc_variant __initconst = {
+	.first_mux_irq	= 19,
+	.nr_mux_irqs	= 13,
+	.mux_valid	= { 0xffffffff, 0xfff80000, 0xffffffff, 0x0000000f },
+};
+
+static int __init sun6i_a31_r_intc_init(struct device_node *node,
+					struct device_node *parent)
+{
+	return sun6i_r_intc_init(node, parent, &sun6i_a31_r_intc_variant);
+}
+IRQCHIP_DECLARE(sun6i_a31_r_intc, "allwinner,sun6i-a31-r-intc", sun6i_a31_r_intc_init);
+
+static const struct sun6i_r_intc_variant sun50i_h6_r_intc_variant __initconst = {
+	.first_mux_irq	= 21,
+	.nr_mux_irqs	= 16,
+	.mux_valid	= { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff },
+};
+
+static int __init sun50i_h6_r_intc_init(struct device_node *node,
+					struct device_node *parent)
+{
+	return sun6i_r_intc_init(node, parent, &sun50i_h6_r_intc_variant);
+}
+IRQCHIP_DECLARE(sun50i_h6_r_intc, "allwinner,sun50i-h6-r-intc", sun50i_h6_r_intc_init);
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 04/10] irqchip/sun6i-r: Add wakeup support
@ 2021-01-03 10:30   ` Samuel Holland
  0 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, Samuel Holland, linux-kernel,
	linux-sunxi, linux-arm-kernel

Maintain bitmaps of wake-enabled IRQs and mux inputs, and program them
to the hardware during the syscore phase of suspend and shutdown. Then
restore the original set of enabled IRQs (only the NMI) during resume.

This serves two purposes. First, it lets power management firmware
running on the ARISC coprocessor know which wakeup sources Linux wants
to have enabled. That way, it can avoid turning them off when it shuts
down the remainder of the clock tree. Second, it preconfigures the
coprocessor's interrupt controller, so the firmware's wakeup logic
is as simple as waiting for an interrupt to arrive.

The suspend/resume logic is not conditional on PM_SLEEP because it is
identical to the init/shutdown logic. Wake IRQs may be enabled during
shutdown to allow powering the board back on. As an example, see
commit a5c5e50cce9d ("Input: gpio-keys - add shutdown callback").

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 drivers/irqchip/irq-sun6i-r.c | 90 ++++++++++++++++++++++++++++++++++-
 1 file changed, 88 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-sun6i-r.c b/drivers/irqchip/irq-sun6i-r.c
index 7490ade7b254..70be0fd228c2 100644
--- a/drivers/irqchip/irq-sun6i-r.c
+++ b/drivers/irqchip/irq-sun6i-r.c
@@ -3,12 +3,14 @@
 // R_INTC driver for Allwinner A31 and newer SoCs
 //
 
+#include <linux/bitmap.h>
 #include <linux/irq.h>
 #include <linux/irqchip.h>
 #include <linux/irqdomain.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <linux/syscore_ops.h>
 
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
@@ -40,9 +42,18 @@
 
 #define SUN6I_NMI_IRQ_BIT		BIT(0)
 
+struct sun6i_r_intc_variant {
+	u32	first_mux_irq;
+	u32	nr_mux_irqs;
+	u32	mux_valid[BITS_TO_U32(SUN6I_NR_MUX_INPUTS)];
+};
+
 static void __iomem *base;
 static irq_hw_number_t nmi_hwirq;
 static u32 nmi_type;
+static DECLARE_BITMAP(wake_irq_enabled, SUN6I_NR_IRQS);
+static DECLARE_BITMAP(wake_mux_enabled, SUN6I_NR_MUX_INPUTS);
+static DECLARE_BITMAP(wake_mux_valid, SUN6I_NR_MUX_INPUTS);
 
 static struct irq_chip sun6i_r_intc_edge_chip;
 static struct irq_chip sun6i_r_intc_level_chip;
@@ -126,6 +137,21 @@ static int sun6i_r_intc_irq_set_type(struct irq_data *data, unsigned int type)
 	return irq_chip_set_type_parent(data, type);
 }
 
+static int sun6i_r_intc_irq_set_wake(struct irq_data *data, unsigned int on)
+{
+	unsigned long offset_from_nmi = data->hwirq - nmi_hwirq;
+
+	if (offset_from_nmi < SUN6I_NR_DIRECT_IRQS)
+		assign_bit(offset_from_nmi, wake_irq_enabled, on);
+	else if (test_bit(data->hwirq, wake_mux_valid))
+		assign_bit(data->hwirq, wake_mux_enabled, on);
+	else
+		/* Not wakeup capable. */
+		return -EPERM;
+
+	return 0;
+}
+
 static struct irq_chip sun6i_r_intc_edge_chip = {
 	.name			= "sun6i-r-intc",
 	.irq_mask		= sun6i_r_intc_irq_mask,
@@ -135,6 +161,7 @@ static struct irq_chip sun6i_r_intc_edge_chip = {
 	.irq_set_type		= sun6i_r_intc_irq_set_type,
 	.irq_get_irqchip_state	= irq_chip_get_parent_state,
 	.irq_set_irqchip_state	= irq_chip_set_parent_state,
+	.irq_set_wake		= sun6i_r_intc_irq_set_wake,
 	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
 	.flags			= IRQCHIP_SET_TYPE_MASKED,
 };
@@ -148,6 +175,7 @@ static struct irq_chip sun6i_r_intc_level_chip = {
 	.irq_set_type		= sun6i_r_intc_irq_set_type,
 	.irq_get_irqchip_state	= irq_chip_get_parent_state,
 	.irq_set_irqchip_state	= irq_chip_set_parent_state,
+	.irq_set_wake		= sun6i_r_intc_irq_set_wake,
 	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
 	.flags			= IRQCHIP_SET_TYPE_MASKED,
 };
@@ -212,6 +240,22 @@ static const struct irq_domain_ops sun6i_r_intc_domain_ops = {
 	.free		= irq_domain_free_irqs_common,
 };
 
+static int sun6i_r_intc_suspend(void)
+{
+	u32 buf[BITS_TO_U32(max(SUN6I_NR_IRQS, SUN6I_NR_MUX_INPUTS))];
+	int i;
+
+	/* Wake IRQs are enabled during system sleep and shutdown. */
+	bitmap_to_arr32(buf, wake_irq_enabled, SUN6I_NR_IRQS);
+	for (i = 0; i < BITS_TO_U32(SUN6I_NR_IRQS); ++i)
+		writel_relaxed(buf[i], base + SUN6I_IRQ_ENABLE(i));
+	bitmap_to_arr32(buf, wake_mux_enabled, SUN6I_NR_MUX_INPUTS);
+	for (i = 0; i < BITS_TO_U32(SUN6I_NR_MUX_INPUTS); ++i)
+		writel_relaxed(buf[i], base + SUN6I_MUX_ENABLE(i));
+
+	return 0;
+}
+
 static void sun6i_r_intc_resume(void)
 {
 	int i;
@@ -222,8 +266,20 @@ static void sun6i_r_intc_resume(void)
 		writel_relaxed(0, base + SUN6I_IRQ_ENABLE(i));
 }
 
+static void sun6i_r_intc_shutdown(void)
+{
+	sun6i_r_intc_suspend();
+}
+
+static struct syscore_ops sun6i_r_intc_syscore_ops = {
+	.suspend	= sun6i_r_intc_suspend,
+	.resume		= sun6i_r_intc_resume,
+	.shutdown	= sun6i_r_intc_shutdown,
+};
+
 static int __init sun6i_r_intc_init(struct device_node *node,
-				    struct device_node *parent)
+				    struct device_node *parent,
+				    const struct sun6i_r_intc_variant *v)
 {
 	struct irq_domain *domain, *parent_domain;
 	struct of_phandle_args parent_irq;
@@ -253,6 +309,9 @@ static int __init sun6i_r_intc_init(struct device_node *node,
 	sun6i_r_intc_nmi_ack();
 	sun6i_r_intc_resume();
 
+	bitmap_set(wake_irq_enabled, v->first_mux_irq, v->nr_mux_irqs);
+	bitmap_from_arr32(wake_mux_valid, v->mux_valid, SUN6I_NR_MUX_INPUTS);
+
 	domain = irq_domain_add_hierarchy(parent_domain, 0,
 					  SUN6I_NR_HWIRQS, node,
 					  &sun6i_r_intc_domain_ops, NULL);
@@ -262,6 +321,33 @@ static int __init sun6i_r_intc_init(struct device_node *node,
 		return -ENOMEM;
 	}
 
+	register_syscore_ops(&sun6i_r_intc_syscore_ops);
+
 	return 0;
 }
-IRQCHIP_DECLARE(sun6i_r_intc, "allwinner,sun6i-a31-r-intc", sun6i_r_intc_init);
+
+static const struct sun6i_r_intc_variant sun6i_a31_r_intc_variant __initconst = {
+	.first_mux_irq	= 19,
+	.nr_mux_irqs	= 13,
+	.mux_valid	= { 0xffffffff, 0xfff80000, 0xffffffff, 0x0000000f },
+};
+
+static int __init sun6i_a31_r_intc_init(struct device_node *node,
+					struct device_node *parent)
+{
+	return sun6i_r_intc_init(node, parent, &sun6i_a31_r_intc_variant);
+}
+IRQCHIP_DECLARE(sun6i_a31_r_intc, "allwinner,sun6i-a31-r-intc", sun6i_a31_r_intc_init);
+
+static const struct sun6i_r_intc_variant sun50i_h6_r_intc_variant __initconst = {
+	.first_mux_irq	= 21,
+	.nr_mux_irqs	= 16,
+	.mux_valid	= { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff },
+};
+
+static int __init sun50i_h6_r_intc_init(struct device_node *node,
+					struct device_node *parent)
+{
+	return sun6i_r_intc_init(node, parent, &sun50i_h6_r_intc_variant);
+}
+IRQCHIP_DECLARE(sun50i_h6_r_intc, "allwinner,sun50i-h6-r-intc", sun50i_h6_r_intc_init);
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 05/10] ARM: dts: sunxi: Rename nmi_intc to r_intc
  2021-01-03 10:30 ` Samuel Holland
@ 2021-01-03 10:30   ` Samuel Holland
  -1 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel,
	linux-sunxi, Samuel Holland

The R_INTC block controls more than just the NMI, and it is a different
hardware block than the NMI INTC found in some other Allwinner SoCs, so
the label "nmi_intc" is inaccurate. Name it "r_intc" to match the
compatible and to match the few references in the vendor documentation.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/arm/boot/dts/sun6i-a31-hummingbird.dts              | 2 +-
 arch/arm/boot/dts/sun6i-a31-m9.dts                       | 2 +-
 arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts         | 2 +-
 arch/arm/boot/dts/sun6i-a31.dtsi                         | 2 +-
 arch/arm/boot/dts/sun6i-a31s-primo81.dts                 | 2 +-
 arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi           | 2 +-
 arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts         | 2 +-
 arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts | 2 +-
 arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi     | 2 +-
 arch/arm/boot/dts/sun8i-a23-a33.dtsi                     | 2 +-
 arch/arm/boot/dts/sun8i-a33-olinuxino.dts                | 2 +-
 arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts           | 2 +-
 arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts             | 2 +-
 arch/arm/boot/dts/sun8i-r16-parrot.dts                   | 2 +-
 arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi     | 2 +-
 15 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
index 73de34ae37fd..486cec6f71e0 100644
--- a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
+++ b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
@@ -226,7 +226,7 @@ &p2wi {
 	axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		x-powers,drive-vbus-en;
 	};
diff --git a/arch/arm/boot/dts/sun6i-a31-m9.dts b/arch/arm/boot/dts/sun6i-a31-m9.dts
index a645c8f4257c..6aeb5a9696f7 100644
--- a/arch/arm/boot/dts/sun6i-a31-m9.dts
+++ b/arch/arm/boot/dts/sun6i-a31-m9.dts
@@ -115,7 +115,7 @@ &p2wi {
 	axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
diff --git a/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts b/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts
index 648f24746234..6c6c1bd22bf6 100644
--- a/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts
+++ b/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts
@@ -115,7 +115,7 @@ &p2wi {
 	axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index f3425a66fc0a..6a733a36d34a 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -1305,7 +1305,7 @@ rtc: rtc@1f00000 {
 			clock-output-names = "osc32k";
 		};
 
-		nmi_intc: interrupt-controller@1f00c00 {
+		r_intc: interrupt-controller@1f00c00 {
 			compatible = "allwinner,sun6i-a31-r-intc";
 			interrupt-controller;
 			#interrupt-cells = <2>;
diff --git a/arch/arm/boot/dts/sun6i-a31s-primo81.dts b/arch/arm/boot/dts/sun6i-a31s-primo81.dts
index bc3170a0b8b5..429a165b79b2 100644
--- a/arch/arm/boot/dts/sun6i-a31s-primo81.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-primo81.dts
@@ -159,7 +159,7 @@ &p2wi {
 	axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		x-powers,drive-vbus-en;
 	};
diff --git a/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi b/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi
index 3099491de8c4..7455c0db4a8a 100644
--- a/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi
@@ -78,7 +78,7 @@ &p2wi {
 	axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
diff --git a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts
index 708caee52425..f1a565e588cd 100644
--- a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts
@@ -148,7 +148,7 @@ &p2wi {
 	axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		x-powers,drive-vbus-en;
diff --git a/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts b/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
index 2504e7189c54..cadc45255d7b 100644
--- a/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
@@ -98,7 +98,7 @@ &p2wi {
 	axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
diff --git a/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi b/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi
index 7de2abd541c1..6bf3fbdd738f 100644
--- a/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi
+++ b/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi
@@ -79,7 +79,7 @@ &p2wi {
 	axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		drivevbus-supply = <&reg_vcc5v0>;
 		x-powers,drive-vbus-en;
diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
index c1362d0f0ff8..a42fac676b31 100644
--- a/arch/arm/boot/dts/sun8i-a23-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
@@ -716,7 +716,7 @@ rtc: rtc@1f00000 {
 			#clock-cells = <1>;
 		};
 
-		nmi_intc: interrupt-controller@1f00c00 {
+		r_intc: interrupt-controller@1f00c00 {
 			compatible = "allwinner,sun6i-a31-r-intc";
 			interrupt-controller;
 			#interrupt-cells = <2>;
diff --git a/arch/arm/boot/dts/sun8i-a33-olinuxino.dts b/arch/arm/boot/dts/sun8i-a33-olinuxino.dts
index a1953b2872d0..2c8db949f99f 100644
--- a/arch/arm/boot/dts/sun8i-a33-olinuxino.dts
+++ b/arch/arm/boot/dts/sun8i-a33-olinuxino.dts
@@ -98,7 +98,7 @@ &r_rsb {
 	axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		x-powers,drive-vbus-en;
diff --git a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
index 785798e3a104..f18ae8a1976e 100644
--- a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
+++ b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
@@ -164,7 +164,7 @@ &r_rsb {
 	axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 	};
diff --git a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
index e1c75f7fa3ca..09ec68c64535 100644
--- a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
+++ b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
@@ -163,7 +163,7 @@ &r_rsb {
 	axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		x-powers,drive-vbus-en;
diff --git a/arch/arm/boot/dts/sun8i-r16-parrot.dts b/arch/arm/boot/dts/sun8i-r16-parrot.dts
index 4f48eec6b2ef..9cdc2ed84847 100644
--- a/arch/arm/boot/dts/sun8i-r16-parrot.dts
+++ b/arch/arm/boot/dts/sun8i-r16-parrot.dts
@@ -164,7 +164,7 @@ &r_rsb {
 	axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		drivevbus-supply = <&reg_vcc5v0>;
 		x-powers,drive-vbus-en;
diff --git a/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi b/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
index b3d8b8f056cd..8175bf307eb1 100644
--- a/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
+++ b/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
@@ -92,7 +92,7 @@ &r_rsb {
 	axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		drivevbus-supply = <&reg_vcc5v0>;
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 05/10] ARM: dts: sunxi: Rename nmi_intc to r_intc
@ 2021-01-03 10:30   ` Samuel Holland
  0 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, Samuel Holland, linux-kernel,
	linux-sunxi, linux-arm-kernel

The R_INTC block controls more than just the NMI, and it is a different
hardware block than the NMI INTC found in some other Allwinner SoCs, so
the label "nmi_intc" is inaccurate. Name it "r_intc" to match the
compatible and to match the few references in the vendor documentation.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/arm/boot/dts/sun6i-a31-hummingbird.dts              | 2 +-
 arch/arm/boot/dts/sun6i-a31-m9.dts                       | 2 +-
 arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts         | 2 +-
 arch/arm/boot/dts/sun6i-a31.dtsi                         | 2 +-
 arch/arm/boot/dts/sun6i-a31s-primo81.dts                 | 2 +-
 arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi           | 2 +-
 arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts         | 2 +-
 arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts | 2 +-
 arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi     | 2 +-
 arch/arm/boot/dts/sun8i-a23-a33.dtsi                     | 2 +-
 arch/arm/boot/dts/sun8i-a33-olinuxino.dts                | 2 +-
 arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts           | 2 +-
 arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts             | 2 +-
 arch/arm/boot/dts/sun8i-r16-parrot.dts                   | 2 +-
 arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi     | 2 +-
 15 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
index 73de34ae37fd..486cec6f71e0 100644
--- a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
+++ b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
@@ -226,7 +226,7 @@ &p2wi {
 	axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		x-powers,drive-vbus-en;
 	};
diff --git a/arch/arm/boot/dts/sun6i-a31-m9.dts b/arch/arm/boot/dts/sun6i-a31-m9.dts
index a645c8f4257c..6aeb5a9696f7 100644
--- a/arch/arm/boot/dts/sun6i-a31-m9.dts
+++ b/arch/arm/boot/dts/sun6i-a31-m9.dts
@@ -115,7 +115,7 @@ &p2wi {
 	axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
diff --git a/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts b/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts
index 648f24746234..6c6c1bd22bf6 100644
--- a/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts
+++ b/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts
@@ -115,7 +115,7 @@ &p2wi {
 	axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index f3425a66fc0a..6a733a36d34a 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -1305,7 +1305,7 @@ rtc: rtc@1f00000 {
 			clock-output-names = "osc32k";
 		};
 
-		nmi_intc: interrupt-controller@1f00c00 {
+		r_intc: interrupt-controller@1f00c00 {
 			compatible = "allwinner,sun6i-a31-r-intc";
 			interrupt-controller;
 			#interrupt-cells = <2>;
diff --git a/arch/arm/boot/dts/sun6i-a31s-primo81.dts b/arch/arm/boot/dts/sun6i-a31s-primo81.dts
index bc3170a0b8b5..429a165b79b2 100644
--- a/arch/arm/boot/dts/sun6i-a31s-primo81.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-primo81.dts
@@ -159,7 +159,7 @@ &p2wi {
 	axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		x-powers,drive-vbus-en;
 	};
diff --git a/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi b/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi
index 3099491de8c4..7455c0db4a8a 100644
--- a/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi
@@ -78,7 +78,7 @@ &p2wi {
 	axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
diff --git a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts
index 708caee52425..f1a565e588cd 100644
--- a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts
@@ -148,7 +148,7 @@ &p2wi {
 	axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		x-powers,drive-vbus-en;
diff --git a/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts b/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
index 2504e7189c54..cadc45255d7b 100644
--- a/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
@@ -98,7 +98,7 @@ &p2wi {
 	axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
diff --git a/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi b/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi
index 7de2abd541c1..6bf3fbdd738f 100644
--- a/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi
+++ b/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi
@@ -79,7 +79,7 @@ &p2wi {
 	axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		drivevbus-supply = <&reg_vcc5v0>;
 		x-powers,drive-vbus-en;
diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
index c1362d0f0ff8..a42fac676b31 100644
--- a/arch/arm/boot/dts/sun8i-a23-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
@@ -716,7 +716,7 @@ rtc: rtc@1f00000 {
 			#clock-cells = <1>;
 		};
 
-		nmi_intc: interrupt-controller@1f00c00 {
+		r_intc: interrupt-controller@1f00c00 {
 			compatible = "allwinner,sun6i-a31-r-intc";
 			interrupt-controller;
 			#interrupt-cells = <2>;
diff --git a/arch/arm/boot/dts/sun8i-a33-olinuxino.dts b/arch/arm/boot/dts/sun8i-a33-olinuxino.dts
index a1953b2872d0..2c8db949f99f 100644
--- a/arch/arm/boot/dts/sun8i-a33-olinuxino.dts
+++ b/arch/arm/boot/dts/sun8i-a33-olinuxino.dts
@@ -98,7 +98,7 @@ &r_rsb {
 	axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		x-powers,drive-vbus-en;
diff --git a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
index 785798e3a104..f18ae8a1976e 100644
--- a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
+++ b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
@@ -164,7 +164,7 @@ &r_rsb {
 	axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 	};
diff --git a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
index e1c75f7fa3ca..09ec68c64535 100644
--- a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
+++ b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
@@ -163,7 +163,7 @@ &r_rsb {
 	axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		x-powers,drive-vbus-en;
diff --git a/arch/arm/boot/dts/sun8i-r16-parrot.dts b/arch/arm/boot/dts/sun8i-r16-parrot.dts
index 4f48eec6b2ef..9cdc2ed84847 100644
--- a/arch/arm/boot/dts/sun8i-r16-parrot.dts
+++ b/arch/arm/boot/dts/sun8i-r16-parrot.dts
@@ -164,7 +164,7 @@ &r_rsb {
 	axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		drivevbus-supply = <&reg_vcc5v0>;
 		x-powers,drive-vbus-en;
diff --git a/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi b/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
index b3d8b8f056cd..8175bf307eb1 100644
--- a/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
+++ b/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
@@ -92,7 +92,7 @@ &r_rsb {
 	axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
-		interrupt-parent = <&nmi_intc>;
+		interrupt-parent = <&r_intc>;
 		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		drivevbus-supply = <&reg_vcc5v0>;
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 06/10] ARM: dts: sunxi: Use the new r_intc binding
  2021-01-03 10:30 ` Samuel Holland
@ 2021-01-03 10:30   ` Samuel Holland
  -1 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel,
	linux-sunxi, Samuel Holland

The binding of R_INTC was updated to allow specifying interrupts other
than the external NMI, since routing those interrupts through the R_INTC
driver allows using them for wakeup.

Update the device trees to use the new binding.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/arm/boot/dts/sun6i-a31-hummingbird.dts              | 2 +-
 arch/arm/boot/dts/sun6i-a31-m9.dts                       | 2 +-
 arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts         | 2 +-
 arch/arm/boot/dts/sun6i-a31.dtsi                         | 2 +-
 arch/arm/boot/dts/sun6i-a31s-primo81.dts                 | 2 +-
 arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi           | 2 +-
 arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts         | 2 +-
 arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts | 2 +-
 arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi     | 2 +-
 arch/arm/boot/dts/sun8i-a23-a33.dtsi                     | 2 +-
 arch/arm/boot/dts/sun8i-a33-olinuxino.dts                | 2 +-
 arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts           | 2 +-
 arch/arm/boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts   | 4 ++--
 arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts             | 4 ++--
 arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts         | 4 ++--
 arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts                | 4 ++--
 arch/arm/boot/dts/sun8i-a83t.dtsi                        | 2 +-
 arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts             | 2 +-
 arch/arm/boot/dts/sun8i-r16-parrot.dts                   | 2 +-
 arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi     | 2 +-
 20 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
index 486cec6f71e0..236ebfc06192 100644
--- a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
+++ b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
@@ -227,7 +227,7 @@ axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		x-powers,drive-vbus-en;
 	};
 };
diff --git a/arch/arm/boot/dts/sun6i-a31-m9.dts b/arch/arm/boot/dts/sun6i-a31-m9.dts
index 6aeb5a9696f7..2436b13cbce1 100644
--- a/arch/arm/boot/dts/sun6i-a31-m9.dts
+++ b/arch/arm/boot/dts/sun6i-a31-m9.dts
@@ -116,7 +116,7 @@ axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts b/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts
index 6c6c1bd22bf6..ce712bdd8cd0 100644
--- a/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts
+++ b/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts
@@ -116,7 +116,7 @@ axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index 6a733a36d34a..faf85c5f4e1e 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -1308,7 +1308,7 @@ rtc: rtc@1f00000 {
 		r_intc: interrupt-controller@1f00c00 {
 			compatible = "allwinner,sun6i-a31-r-intc";
 			interrupt-controller;
-			#interrupt-cells = <2>;
+			#interrupt-cells = <3>;
 			reg = <0x01f00c00 0x400>;
 			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
 		};
diff --git a/arch/arm/boot/dts/sun6i-a31s-primo81.dts b/arch/arm/boot/dts/sun6i-a31s-primo81.dts
index 429a165b79b2..c5c85eb44cc7 100644
--- a/arch/arm/boot/dts/sun6i-a31s-primo81.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-primo81.dts
@@ -160,7 +160,7 @@ axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		x-powers,drive-vbus-en;
 	};
 };
diff --git a/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi b/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi
index 7455c0db4a8a..227ad489731c 100644
--- a/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi
@@ -79,7 +79,7 @@ axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts
index f1a565e588cd..1f7cfaa86d3d 100644
--- a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts
@@ -149,7 +149,7 @@ axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		x-powers,drive-vbus-en;
 	};
diff --git a/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts b/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
index cadc45255d7b..0b61f5368d44 100644
--- a/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
@@ -99,7 +99,7 @@ axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi b/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi
index 6bf3fbdd738f..f38d19c6be8c 100644
--- a/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi
+++ b/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi
@@ -80,7 +80,7 @@ axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		drivevbus-supply = <&reg_vcc5v0>;
 		x-powers,drive-vbus-en;
 	};
diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
index a42fac676b31..a84c90a660ca 100644
--- a/arch/arm/boot/dts/sun8i-a23-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
@@ -719,7 +719,7 @@ rtc: rtc@1f00000 {
 		r_intc: interrupt-controller@1f00c00 {
 			compatible = "allwinner,sun6i-a31-r-intc";
 			interrupt-controller;
-			#interrupt-cells = <2>;
+			#interrupt-cells = <3>;
 			reg = <0x01f00c00 0x400>;
 			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
 		};
diff --git a/arch/arm/boot/dts/sun8i-a33-olinuxino.dts b/arch/arm/boot/dts/sun8i-a33-olinuxino.dts
index 2c8db949f99f..810fada3db00 100644
--- a/arch/arm/boot/dts/sun8i-a33-olinuxino.dts
+++ b/arch/arm/boot/dts/sun8i-a33-olinuxino.dts
@@ -99,7 +99,7 @@ axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		x-powers,drive-vbus-en;
 	};
diff --git a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
index f18ae8a1976e..66fec9a8c777 100644
--- a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
+++ b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
@@ -165,7 +165,7 @@ axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 	};
 };
diff --git a/arch/arm/boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts b/arch/arm/boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts
index 9c006fc18821..c31c97d16024 100644
--- a/arch/arm/boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts
+++ b/arch/arm/boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts
@@ -122,7 +122,7 @@ axp81x: pmic@3a3 {
 		compatible = "x-powers,axp818", "x-powers,axp813";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		swin-supply = <&reg_dcdc1>;
 	};
@@ -142,7 +142,7 @@ ac100_codec: codec {
 		ac100_rtc: rtc {
 			compatible = "x-powers,ac100-rtc";
 			interrupt-parent = <&r_intc>;
-			interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 			clocks = <&ac100_codec>;
 			#clock-cells = <1>;
 			clock-output-names = "cko1_rtc",
diff --git a/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts b/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
index 431f70234d36..2e8e1134a852 100644
--- a/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
+++ b/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
@@ -203,7 +203,7 @@ axp81x: pmic@3a3 {
 		compatible = "x-powers,axp813";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		fldoin-supply = <&reg_dcdc5>;
 		swin-supply = <&reg_dcdc1>;
@@ -225,7 +225,7 @@ ac100_codec: codec {
 		ac100_rtc: rtc {
 			compatible = "x-powers,ac100-rtc";
 			interrupt-parent = <&r_intc>;
-			interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 			clocks = <&ac100_codec>;
 			#clock-cells = <1>;
 			clock-output-names = "cko1_rtc",
diff --git a/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts b/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts
index d8326a5c681d..f15eb782bca3 100644
--- a/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts
+++ b/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts
@@ -239,7 +239,7 @@ axp81x: pmic@3a3 {
 		compatible = "x-powers,axp818", "x-powers,axp813";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		swin-supply = <&reg_dcdc1>;
 		x-powers,drive-vbus-en;
@@ -260,7 +260,7 @@ ac100_codec: codec {
 		ac100_rtc: rtc {
 			compatible = "x-powers,ac100-rtc";
 			interrupt-parent = <&r_intc>;
-			interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 			clocks = <&ac100_codec>;
 			#clock-cells = <1>;
 			clock-output-names = "cko1_rtc",
diff --git a/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts b/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts
index bfc9bb277a49..1a146e200cde 100644
--- a/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts
+++ b/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts
@@ -263,7 +263,7 @@ axp81x: pmic@3a3 {
 		compatible = "x-powers,axp813";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		swin-supply = <&reg_dcdc1>;
 		x-powers,drive-vbus-en;
 	};
@@ -283,7 +283,7 @@ ac100_codec: codec {
 		ac100_rtc: rtc {
 			compatible = "x-powers,ac100-rtc";
 			interrupt-parent = <&r_intc>;
-			interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 			clocks = <&ac100_codec>;
 			#clock-cells = <1>;
 			clock-output-names = "cko1_rtc",
diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index c010b27fdb6a..0fce227f56d4 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -1114,7 +1114,7 @@ r_intc: interrupt-controller@1f00c00 {
 			compatible = "allwinner,sun8i-a83t-r-intc",
 				     "allwinner,sun6i-a31-r-intc";
 			interrupt-controller;
-			#interrupt-cells = <2>;
+			#interrupt-cells = <3>;
 			reg = <0x01f00c00 0x400>;
 			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
 		};
diff --git a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
index 09ec68c64535..8e8ecdcd3a83 100644
--- a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
+++ b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
@@ -164,7 +164,7 @@ axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		x-powers,drive-vbus-en;
 	};
diff --git a/arch/arm/boot/dts/sun8i-r16-parrot.dts b/arch/arm/boot/dts/sun8i-r16-parrot.dts
index 9cdc2ed84847..de4bce5f89a8 100644
--- a/arch/arm/boot/dts/sun8i-r16-parrot.dts
+++ b/arch/arm/boot/dts/sun8i-r16-parrot.dts
@@ -165,7 +165,7 @@ axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		drivevbus-supply = <&reg_vcc5v0>;
 		x-powers,drive-vbus-en;
 	};
diff --git a/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi b/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
index 8175bf307eb1..d71ea3637850 100644
--- a/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
+++ b/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
@@ -93,7 +93,7 @@ axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		drivevbus-supply = <&reg_vcc5v0>;
 		x-powers,drive-vbus-en;
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 06/10] ARM: dts: sunxi: Use the new r_intc binding
@ 2021-01-03 10:30   ` Samuel Holland
  0 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, Samuel Holland, linux-kernel,
	linux-sunxi, linux-arm-kernel

The binding of R_INTC was updated to allow specifying interrupts other
than the external NMI, since routing those interrupts through the R_INTC
driver allows using them for wakeup.

Update the device trees to use the new binding.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/arm/boot/dts/sun6i-a31-hummingbird.dts              | 2 +-
 arch/arm/boot/dts/sun6i-a31-m9.dts                       | 2 +-
 arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts         | 2 +-
 arch/arm/boot/dts/sun6i-a31.dtsi                         | 2 +-
 arch/arm/boot/dts/sun6i-a31s-primo81.dts                 | 2 +-
 arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi           | 2 +-
 arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts         | 2 +-
 arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts | 2 +-
 arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi     | 2 +-
 arch/arm/boot/dts/sun8i-a23-a33.dtsi                     | 2 +-
 arch/arm/boot/dts/sun8i-a33-olinuxino.dts                | 2 +-
 arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts           | 2 +-
 arch/arm/boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts   | 4 ++--
 arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts             | 4 ++--
 arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts         | 4 ++--
 arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts                | 4 ++--
 arch/arm/boot/dts/sun8i-a83t.dtsi                        | 2 +-
 arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts             | 2 +-
 arch/arm/boot/dts/sun8i-r16-parrot.dts                   | 2 +-
 arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi     | 2 +-
 20 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
index 486cec6f71e0..236ebfc06192 100644
--- a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
+++ b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
@@ -227,7 +227,7 @@ axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		x-powers,drive-vbus-en;
 	};
 };
diff --git a/arch/arm/boot/dts/sun6i-a31-m9.dts b/arch/arm/boot/dts/sun6i-a31-m9.dts
index 6aeb5a9696f7..2436b13cbce1 100644
--- a/arch/arm/boot/dts/sun6i-a31-m9.dts
+++ b/arch/arm/boot/dts/sun6i-a31-m9.dts
@@ -116,7 +116,7 @@ axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts b/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts
index 6c6c1bd22bf6..ce712bdd8cd0 100644
--- a/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts
+++ b/arch/arm/boot/dts/sun6i-a31-mele-a1000g-quad.dts
@@ -116,7 +116,7 @@ axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index 6a733a36d34a..faf85c5f4e1e 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -1308,7 +1308,7 @@ rtc: rtc@1f00000 {
 		r_intc: interrupt-controller@1f00c00 {
 			compatible = "allwinner,sun6i-a31-r-intc";
 			interrupt-controller;
-			#interrupt-cells = <2>;
+			#interrupt-cells = <3>;
 			reg = <0x01f00c00 0x400>;
 			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
 		};
diff --git a/arch/arm/boot/dts/sun6i-a31s-primo81.dts b/arch/arm/boot/dts/sun6i-a31s-primo81.dts
index 429a165b79b2..c5c85eb44cc7 100644
--- a/arch/arm/boot/dts/sun6i-a31s-primo81.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-primo81.dts
@@ -160,7 +160,7 @@ axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		x-powers,drive-vbus-en;
 	};
 };
diff --git a/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi b/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi
index 7455c0db4a8a..227ad489731c 100644
--- a/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi
@@ -79,7 +79,7 @@ axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts
index f1a565e588cd..1f7cfaa86d3d 100644
--- a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts
@@ -149,7 +149,7 @@ axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		x-powers,drive-vbus-en;
 	};
diff --git a/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts b/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
index cadc45255d7b..0b61f5368d44 100644
--- a/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
+++ b/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
@@ -99,7 +99,7 @@ axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
diff --git a/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi b/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi
index 6bf3fbdd738f..f38d19c6be8c 100644
--- a/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi
+++ b/arch/arm/boot/dts/sun6i-reference-design-tablet.dtsi
@@ -80,7 +80,7 @@ axp22x: pmic@68 {
 		compatible = "x-powers,axp221";
 		reg = <0x68>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		drivevbus-supply = <&reg_vcc5v0>;
 		x-powers,drive-vbus-en;
 	};
diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
index a42fac676b31..a84c90a660ca 100644
--- a/arch/arm/boot/dts/sun8i-a23-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
@@ -719,7 +719,7 @@ rtc: rtc@1f00000 {
 		r_intc: interrupt-controller@1f00c00 {
 			compatible = "allwinner,sun6i-a31-r-intc";
 			interrupt-controller;
-			#interrupt-cells = <2>;
+			#interrupt-cells = <3>;
 			reg = <0x01f00c00 0x400>;
 			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
 		};
diff --git a/arch/arm/boot/dts/sun8i-a33-olinuxino.dts b/arch/arm/boot/dts/sun8i-a33-olinuxino.dts
index 2c8db949f99f..810fada3db00 100644
--- a/arch/arm/boot/dts/sun8i-a33-olinuxino.dts
+++ b/arch/arm/boot/dts/sun8i-a33-olinuxino.dts
@@ -99,7 +99,7 @@ axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		x-powers,drive-vbus-en;
 	};
diff --git a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
index f18ae8a1976e..66fec9a8c777 100644
--- a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
+++ b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
@@ -165,7 +165,7 @@ axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 	};
 };
diff --git a/arch/arm/boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts b/arch/arm/boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts
index 9c006fc18821..c31c97d16024 100644
--- a/arch/arm/boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts
+++ b/arch/arm/boot/dts/sun8i-a83t-allwinner-h8homlet-v2.dts
@@ -122,7 +122,7 @@ axp81x: pmic@3a3 {
 		compatible = "x-powers,axp818", "x-powers,axp813";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		swin-supply = <&reg_dcdc1>;
 	};
@@ -142,7 +142,7 @@ ac100_codec: codec {
 		ac100_rtc: rtc {
 			compatible = "x-powers,ac100-rtc";
 			interrupt-parent = <&r_intc>;
-			interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 			clocks = <&ac100_codec>;
 			#clock-cells = <1>;
 			clock-output-names = "cko1_rtc",
diff --git a/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts b/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
index 431f70234d36..2e8e1134a852 100644
--- a/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
+++ b/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
@@ -203,7 +203,7 @@ axp81x: pmic@3a3 {
 		compatible = "x-powers,axp813";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		fldoin-supply = <&reg_dcdc5>;
 		swin-supply = <&reg_dcdc1>;
@@ -225,7 +225,7 @@ ac100_codec: codec {
 		ac100_rtc: rtc {
 			compatible = "x-powers,ac100-rtc";
 			interrupt-parent = <&r_intc>;
-			interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 			clocks = <&ac100_codec>;
 			#clock-cells = <1>;
 			clock-output-names = "cko1_rtc",
diff --git a/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts b/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts
index d8326a5c681d..f15eb782bca3 100644
--- a/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts
+++ b/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts
@@ -239,7 +239,7 @@ axp81x: pmic@3a3 {
 		compatible = "x-powers,axp818", "x-powers,axp813";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		swin-supply = <&reg_dcdc1>;
 		x-powers,drive-vbus-en;
@@ -260,7 +260,7 @@ ac100_codec: codec {
 		ac100_rtc: rtc {
 			compatible = "x-powers,ac100-rtc";
 			interrupt-parent = <&r_intc>;
-			interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 			clocks = <&ac100_codec>;
 			#clock-cells = <1>;
 			clock-output-names = "cko1_rtc",
diff --git a/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts b/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts
index bfc9bb277a49..1a146e200cde 100644
--- a/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts
+++ b/arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts
@@ -263,7 +263,7 @@ axp81x: pmic@3a3 {
 		compatible = "x-powers,axp813";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		swin-supply = <&reg_dcdc1>;
 		x-powers,drive-vbus-en;
 	};
@@ -283,7 +283,7 @@ ac100_codec: codec {
 		ac100_rtc: rtc {
 			compatible = "x-powers,ac100-rtc";
 			interrupt-parent = <&r_intc>;
-			interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 			clocks = <&ac100_codec>;
 			#clock-cells = <1>;
 			clock-output-names = "cko1_rtc",
diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index c010b27fdb6a..0fce227f56d4 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -1114,7 +1114,7 @@ r_intc: interrupt-controller@1f00c00 {
 			compatible = "allwinner,sun8i-a83t-r-intc",
 				     "allwinner,sun6i-a31-r-intc";
 			interrupt-controller;
-			#interrupt-cells = <2>;
+			#interrupt-cells = <3>;
 			reg = <0x01f00c00 0x400>;
 			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
 		};
diff --git a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
index 09ec68c64535..8e8ecdcd3a83 100644
--- a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
+++ b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
@@ -164,7 +164,7 @@ axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		x-powers,drive-vbus-en;
 	};
diff --git a/arch/arm/boot/dts/sun8i-r16-parrot.dts b/arch/arm/boot/dts/sun8i-r16-parrot.dts
index 9cdc2ed84847..de4bce5f89a8 100644
--- a/arch/arm/boot/dts/sun8i-r16-parrot.dts
+++ b/arch/arm/boot/dts/sun8i-r16-parrot.dts
@@ -165,7 +165,7 @@ axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		drivevbus-supply = <&reg_vcc5v0>;
 		x-powers,drive-vbus-en;
 	};
diff --git a/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi b/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
index 8175bf307eb1..d71ea3637850 100644
--- a/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
+++ b/arch/arm/boot/dts/sun8i-reference-design-tablet.dtsi
@@ -93,7 +93,7 @@ axp22x: pmic@3a3 {
 		compatible = "x-powers,axp223";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		eldoin-supply = <&reg_dcdc1>;
 		drivevbus-supply = <&reg_vcc5v0>;
 		x-powers,drive-vbus-en;
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 07/10] ARM: dts: sunxi: h3/h5: Add r_intc node
  2021-01-03 10:30 ` Samuel Holland
@ 2021-01-03 10:30   ` Samuel Holland
  -1 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel,
	linux-sunxi, Samuel Holland

The H3 and H5 SoCs have an additional interrupt controller in the RTC
power domain that can be used to enable wakeup for certain IRQs.

Add a node for it.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/arm/boot/dts/sunxi-h3-h5.dtsi | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
index 9be13378d4df..4bf25c5b873e 100644
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -859,6 +859,15 @@ rtc: rtc@1f00000 {
 			#clock-cells = <1>;
 		};
 
+		r_intc: interrupt-controller@1f00c00 {
+			compatible = "allwinner,sun8i-h3-r-intc",
+				     "allwinner,sun6i-a31-r-intc";
+			interrupt-controller;
+			#interrupt-cells = <3>;
+			reg = <0x01f00c00 0x400>;
+			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
 		r_ccu: clock@1f01400 {
 			compatible = "allwinner,sun8i-h3-r-ccu";
 			reg = <0x01f01400 0x100>;
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 07/10] ARM: dts: sunxi: h3/h5: Add r_intc node
@ 2021-01-03 10:30   ` Samuel Holland
  0 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, Samuel Holland, linux-kernel,
	linux-sunxi, linux-arm-kernel

The H3 and H5 SoCs have an additional interrupt controller in the RTC
power domain that can be used to enable wakeup for certain IRQs.

Add a node for it.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/arm/boot/dts/sunxi-h3-h5.dtsi | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
index 9be13378d4df..4bf25c5b873e 100644
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -859,6 +859,15 @@ rtc: rtc@1f00000 {
 			#clock-cells = <1>;
 		};
 
+		r_intc: interrupt-controller@1f00c00 {
+			compatible = "allwinner,sun8i-h3-r-intc",
+				     "allwinner,sun6i-a31-r-intc";
+			interrupt-controller;
+			#interrupt-cells = <3>;
+			reg = <0x01f00c00 0x400>;
+			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
 		r_ccu: clock@1f01400 {
 			compatible = "allwinner,sun8i-h3-r-ccu";
 			reg = <0x01f01400 0x100>;
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 08/10] ARM: dts: sunxi: Move wakeup-capable IRQs to r_intc
  2021-01-03 10:30 ` Samuel Holland
@ 2021-01-03 10:30   ` Samuel Holland
  -1 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel,
	linux-sunxi, Samuel Holland

All IRQs that can be used to wake up the system must be routed through
r_intc, so they are visible to firmware while the system is suspended.

In addition to the external NMI input, which is already routed through
r_intc, these include PIO and R_PIO (gpio-keys), the LRADC, and the RTC.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/arm/boot/dts/sun6i-a31.dtsi     | 4 ++++
 arch/arm/boot/dts/sun8i-a23-a33.dtsi | 4 ++++
 arch/arm/boot/dts/sun8i-a83t.dtsi    | 3 +++
 arch/arm/boot/dts/sunxi-h3-h5.dtsi   | 3 +++
 4 files changed, 14 insertions(+)

diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index faf85c5f4e1e..50324688c28a 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -611,6 +611,7 @@ ccu: clock@1c20000 {
 		pio: pinctrl@1c20800 {
 			compatible = "allwinner,sun6i-a31-pinctrl";
 			reg = <0x01c20800 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
@@ -802,6 +803,7 @@ i2s1: i2s@1c22400 {
 		lradc: lradc@1c22800 {
 			compatible = "allwinner,sun4i-a10-lradc-keys";
 			reg = <0x01c22800 0x100>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
@@ -1299,6 +1301,7 @@ rtc: rtc@1f00000 {
 			#clock-cells = <1>;
 			compatible = "allwinner,sun6i-a31-rtc";
 			reg = <0x01f00000 0x54>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&osc32k>;
@@ -1383,6 +1386,7 @@ ir: ir@1f02000 {
 		r_pio: pinctrl@1f02c00 {
 			compatible = "allwinner,sun6i-a31-r-pinctrl";
 			reg = <0x01f02c00 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb0_gates 0>, <&osc24M>, <&rtc 0>;
diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
index a84c90a660ca..4461d5098b20 100644
--- a/arch/arm/boot/dts/sun8i-a23-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
@@ -338,6 +338,7 @@ ccu: clock@1c20000 {
 		pio: pinctrl@1c20800 {
 			/* compatible gets set in SoC specific dtsi file */
 			reg = <0x01c20800 0x400>;
+			interrupt-parent = <&r_intc>;
 			/* interrupts get set in SoC specific dtsi file */
 			clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&rtc 0>;
 			clock-names = "apb", "hosc", "losc";
@@ -473,6 +474,7 @@ pwm: pwm@1c21400 {
 		lradc: lradc@1c22800 {
 			compatible = "allwinner,sun4i-a10-lradc-keys";
 			reg = <0x01c22800 0x100>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
@@ -709,6 +711,7 @@ drc0_out_tcon0: endpoint {
 		rtc: rtc@1f00000 {
 			compatible = "allwinner,sun8i-a23-rtc";
 			reg = <0x01f00000 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
 			clock-output-names = "osc32k", "osc32k-out";
@@ -805,6 +808,7 @@ r_i2c: i2c@1f02400 {
 		r_pio: pinctrl@1f02c00 {
 			compatible = "allwinner,sun8i-a23-r-pinctrl";
 			reg = <0x01f02c00 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb0_gates 0>, <&osc24M>, <&rtc 0>;
 			clock-names = "apb", "hosc", "losc";
diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index 0fce227f56d4..2c05e296b3d8 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -708,6 +708,7 @@ ccu: clock@1c20000 {
 
 		pio: pinctrl@1c20800 {
 			compatible = "allwinner,sun8i-a83t-pinctrl";
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
@@ -1150,6 +1151,7 @@ r_cir: ir@1f02000 {
 		r_lradc: lradc@1f03c00 {
 			compatible = "allwinner,sun8i-a83t-r-lradc";
 			reg = <0x01f03c00 0x100>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
@@ -1157,6 +1159,7 @@ r_lradc: lradc@1f03c00 {
 		r_pio: pinctrl@1f02c00 {
 			compatible = "allwinner,sun8i-a83t-r-pinctrl";
 			reg = <0x01f02c00 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&r_ccu CLK_APB0_PIO>, <&osc24M>,
 				 <&osc16Md512>;
diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
index 4bf25c5b873e..c7428df9469e 100644
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -395,6 +395,7 @@ ccu: clock@1c20000 {
 		pio: pinctrl@1c20800 {
 			/* compatible is in per SoC .dtsi file */
 			reg = <0x01c20800 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&rtc 0>;
@@ -852,6 +853,7 @@ hdmi_phy: hdmi-phy@1ef0000 {
 		rtc: rtc@1f00000 {
 			/* compatible is in per SoC .dtsi file */
 			reg = <0x01f00000 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
 			clock-output-names = "osc32k", "osc32k-out", "iosc";
@@ -909,6 +911,7 @@ r_i2c: i2c@1f02400 {
 		r_pio: pinctrl@1f02c00 {
 			compatible = "allwinner,sun8i-h3-r-pinctrl";
 			reg = <0x01f02c00 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&r_ccu CLK_APB0_PIO>, <&osc24M>, <&rtc 0>;
 			clock-names = "apb", "hosc", "losc";
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 08/10] ARM: dts: sunxi: Move wakeup-capable IRQs to r_intc
@ 2021-01-03 10:30   ` Samuel Holland
  0 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:30 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, Samuel Holland, linux-kernel,
	linux-sunxi, linux-arm-kernel

All IRQs that can be used to wake up the system must be routed through
r_intc, so they are visible to firmware while the system is suspended.

In addition to the external NMI input, which is already routed through
r_intc, these include PIO and R_PIO (gpio-keys), the LRADC, and the RTC.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/arm/boot/dts/sun6i-a31.dtsi     | 4 ++++
 arch/arm/boot/dts/sun8i-a23-a33.dtsi | 4 ++++
 arch/arm/boot/dts/sun8i-a83t.dtsi    | 3 +++
 arch/arm/boot/dts/sunxi-h3-h5.dtsi   | 3 +++
 4 files changed, 14 insertions(+)

diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index faf85c5f4e1e..50324688c28a 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -611,6 +611,7 @@ ccu: clock@1c20000 {
 		pio: pinctrl@1c20800 {
 			compatible = "allwinner,sun6i-a31-pinctrl";
 			reg = <0x01c20800 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
@@ -802,6 +803,7 @@ i2s1: i2s@1c22400 {
 		lradc: lradc@1c22800 {
 			compatible = "allwinner,sun4i-a10-lradc-keys";
 			reg = <0x01c22800 0x100>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
@@ -1299,6 +1301,7 @@ rtc: rtc@1f00000 {
 			#clock-cells = <1>;
 			compatible = "allwinner,sun6i-a31-rtc";
 			reg = <0x01f00000 0x54>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&osc32k>;
@@ -1383,6 +1386,7 @@ ir: ir@1f02000 {
 		r_pio: pinctrl@1f02c00 {
 			compatible = "allwinner,sun6i-a31-r-pinctrl";
 			reg = <0x01f02c00 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb0_gates 0>, <&osc24M>, <&rtc 0>;
diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
index a84c90a660ca..4461d5098b20 100644
--- a/arch/arm/boot/dts/sun8i-a23-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
@@ -338,6 +338,7 @@ ccu: clock@1c20000 {
 		pio: pinctrl@1c20800 {
 			/* compatible gets set in SoC specific dtsi file */
 			reg = <0x01c20800 0x400>;
+			interrupt-parent = <&r_intc>;
 			/* interrupts get set in SoC specific dtsi file */
 			clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&rtc 0>;
 			clock-names = "apb", "hosc", "losc";
@@ -473,6 +474,7 @@ pwm: pwm@1c21400 {
 		lradc: lradc@1c22800 {
 			compatible = "allwinner,sun4i-a10-lradc-keys";
 			reg = <0x01c22800 0x100>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
@@ -709,6 +711,7 @@ drc0_out_tcon0: endpoint {
 		rtc: rtc@1f00000 {
 			compatible = "allwinner,sun8i-a23-rtc";
 			reg = <0x01f00000 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
 			clock-output-names = "osc32k", "osc32k-out";
@@ -805,6 +808,7 @@ r_i2c: i2c@1f02400 {
 		r_pio: pinctrl@1f02c00 {
 			compatible = "allwinner,sun8i-a23-r-pinctrl";
 			reg = <0x01f02c00 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&apb0_gates 0>, <&osc24M>, <&rtc 0>;
 			clock-names = "apb", "hosc", "losc";
diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index 0fce227f56d4..2c05e296b3d8 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -708,6 +708,7 @@ ccu: clock@1c20000 {
 
 		pio: pinctrl@1c20800 {
 			compatible = "allwinner,sun8i-a83t-pinctrl";
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
@@ -1150,6 +1151,7 @@ r_cir: ir@1f02000 {
 		r_lradc: lradc@1f03c00 {
 			compatible = "allwinner,sun8i-a83t-r-lradc";
 			reg = <0x01f03c00 0x100>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
@@ -1157,6 +1159,7 @@ r_lradc: lradc@1f03c00 {
 		r_pio: pinctrl@1f02c00 {
 			compatible = "allwinner,sun8i-a83t-r-pinctrl";
 			reg = <0x01f02c00 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&r_ccu CLK_APB0_PIO>, <&osc24M>,
 				 <&osc16Md512>;
diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
index 4bf25c5b873e..c7428df9469e 100644
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -395,6 +395,7 @@ ccu: clock@1c20000 {
 		pio: pinctrl@1c20800 {
 			/* compatible is in per SoC .dtsi file */
 			reg = <0x01c20800 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&rtc 0>;
@@ -852,6 +853,7 @@ hdmi_phy: hdmi-phy@1ef0000 {
 		rtc: rtc@1f00000 {
 			/* compatible is in per SoC .dtsi file */
 			reg = <0x01f00000 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
 			clock-output-names = "osc32k", "osc32k-out", "iosc";
@@ -909,6 +911,7 @@ r_i2c: i2c@1f02400 {
 		r_pio: pinctrl@1f02c00 {
 			compatible = "allwinner,sun8i-h3-r-pinctrl";
 			reg = <0x01f02c00 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&r_ccu CLK_APB0_PIO>, <&osc24M>, <&rtc 0>;
 			clock-names = "apb", "hosc", "losc";
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 09/10] arm64: dts: allwinner: Use the new r_intc binding
  2021-01-03 10:30 ` Samuel Holland
@ 2021-01-03 10:31   ` Samuel Holland
  -1 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:31 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel,
	linux-sunxi, Samuel Holland

The binding of R_INTC was updated to allow specifying interrupts other
than the external NMI, since routing those interrupts through the R_INTC
driver allows using them for wakeup.

Update the device trees to use the new binding.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/arm64/boot/dts/allwinner/sun50i-a64-amarula-relic.dts | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts  | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts    | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts     | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts  | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts        | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts      | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi    | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-pinetab.dts       | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-sopine.dtsi       | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-teres-i.dts       | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi              | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts    | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts     | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi      | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts       | 4 ++--
 arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi               | 2 +-
 17 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-amarula-relic.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-amarula-relic.dts
index c7bd73f35ed8..f17cc89f472d 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-amarula-relic.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-amarula-relic.dts
@@ -173,7 +173,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		x-powers,drive-vbus-en; /* set N_VBUSEN as output pin */
 	};
 };
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
index e5e840b9fbb4..e45bef292aa3 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
@@ -191,7 +191,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		x-powers,drive-vbus-en; /* set N_VBUSEN as output pin */
 	};
 };
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts
index e58db8a6cab6..57b64c57781b 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts
@@ -152,7 +152,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts
index f3f8e177ab61..ec7e2c0e82c1 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts
@@ -185,7 +185,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		x-powers,drive-vbus-en;	/* set N_VBUSEN as output pin */
 	};
 };
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts
index 70e31743f0ba..097a5511523a 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts
@@ -192,7 +192,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		x-powers,drive-vbus-en; /* set N_VBUSEN as output pin */
 	};
 };
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts
index 329cf276561e..2accb5ddf783 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts
@@ -139,7 +139,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts
index 896f34fd9fc3..d1f85018257c 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts
@@ -248,7 +248,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
index 2dfe9bae8c67..b7124ec2cea2 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
@@ -288,7 +288,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinetab.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinetab.dts
index 0494bfaf2ffa..5514075a2ae1 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinetab.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinetab.dts
@@ -266,7 +266,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		x-powers,drive-vbus-en;
 	};
 };
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine.dtsi
index c48692b06e1f..a820f30c3e8a 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine.dtsi
@@ -46,7 +46,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-teres-i.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-teres-i.dts
index a1864a89fb89..03f733ee44d9 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-teres-i.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-teres-i.dts
@@ -205,7 +205,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		wakeup-source;
 	};
 };
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index 51cc30e84e26..fd4bf90163d5 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -1215,7 +1215,7 @@ r_intc: interrupt-controller@1f00c00 {
 			compatible = "allwinner,sun50i-a64-r-intc",
 				     "allwinner,sun6i-a31-r-intc";
 			interrupt-controller;
-			#interrupt-cells = <2>;
+			#interrupt-cells = <3>;
 			reg = <0x01f00c00 0x400>;
 			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
 		};
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts
index 7c9dbde645b5..5c39f5f3f22c 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts
@@ -157,7 +157,7 @@ axp805: pmic@36 {
 		compatible = "x-powers,axp805", "x-powers,axp806";
 		reg = <0x36>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>;
 		interrupt-controller;
 		#interrupt-cells = <1>;
 		x-powers,self-working-mode;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
index 15c9dd8c4479..41aaad43b5d5 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
@@ -182,7 +182,7 @@ axp805: pmic@36 {
 		compatible = "x-powers,axp805", "x-powers,axp806";
 		reg = <0x36>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>;
 		interrupt-controller;
 		#interrupt-cells = <1>;
 		x-powers,self-working-mode;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi
index ebc120a9232f..1ee19f5fc6ab 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi
@@ -119,7 +119,7 @@ axp805: pmic@36 {
 		compatible = "x-powers,axp805", "x-powers,axp806";
 		reg = <0x36>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>;
 		interrupt-controller;
 		#interrupt-cells = <1>;
 		x-powers,self-working-mode;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
index 961732c52aa0..0b9117e986b7 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
@@ -167,7 +167,7 @@ axp805: pmic@36 {
 		compatible = "x-powers,axp805", "x-powers,axp806";
 		reg = <0x36>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>;
 		interrupt-controller;
 		#interrupt-cells = <1>;
 		x-powers,self-working-mode;
@@ -280,7 +280,7 @@ pcf8563: rtc@51 {
 		compatible = "nxp,pcf8563";
 		reg = <0x51>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>;
 		#clock-cells = <0>;
 	};
 };
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index 8a62a9fbe347..d838bcc7aa60 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -923,7 +923,7 @@ r_intc: interrupt-controller@7021000 {
 			compatible = "allwinner,sun50i-h6-r-intc",
 				     "allwinner,sun6i-a31-r-intc";
 			interrupt-controller;
-			#interrupt-cells = <2>;
+			#interrupt-cells = <3>;
 			reg = <0x07021000 0x400>;
 			interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
 		};
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 09/10] arm64: dts: allwinner: Use the new r_intc binding
@ 2021-01-03 10:31   ` Samuel Holland
  0 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:31 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, Samuel Holland, linux-kernel,
	linux-sunxi, linux-arm-kernel

The binding of R_INTC was updated to allow specifying interrupts other
than the external NMI, since routing those interrupts through the R_INTC
driver allows using them for wakeup.

Update the device trees to use the new binding.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/arm64/boot/dts/allwinner/sun50i-a64-amarula-relic.dts | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts  | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts    | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts     | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts  | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts        | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts      | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi    | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-pinetab.dts       | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-sopine.dtsi       | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64-teres-i.dts       | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi              | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts    | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts     | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi      | 2 +-
 arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts       | 4 ++--
 arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi               | 2 +-
 17 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-amarula-relic.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-amarula-relic.dts
index c7bd73f35ed8..f17cc89f472d 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-amarula-relic.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-amarula-relic.dts
@@ -173,7 +173,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		x-powers,drive-vbus-en; /* set N_VBUSEN as output pin */
 	};
 };
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
index e5e840b9fbb4..e45bef292aa3 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
@@ -191,7 +191,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		x-powers,drive-vbus-en; /* set N_VBUSEN as output pin */
 	};
 };
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts
index e58db8a6cab6..57b64c57781b 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts
@@ -152,7 +152,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts
index f3f8e177ab61..ec7e2c0e82c1 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts
@@ -185,7 +185,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		x-powers,drive-vbus-en;	/* set N_VBUSEN as output pin */
 	};
 };
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts
index 70e31743f0ba..097a5511523a 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts
@@ -192,7 +192,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		x-powers,drive-vbus-en; /* set N_VBUSEN as output pin */
 	};
 };
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts
index 329cf276561e..2accb5ddf783 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts
@@ -139,7 +139,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts
index 896f34fd9fc3..d1f85018257c 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinebook.dts
@@ -248,7 +248,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
index 2dfe9bae8c67..b7124ec2cea2 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
@@ -288,7 +288,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinetab.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinetab.dts
index 0494bfaf2ffa..5514075a2ae1 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinetab.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinetab.dts
@@ -266,7 +266,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		x-powers,drive-vbus-en;
 	};
 };
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine.dtsi
index c48692b06e1f..a820f30c3e8a 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine.dtsi
@@ -46,7 +46,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 	};
 };
 
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-teres-i.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-teres-i.dts
index a1864a89fb89..03f733ee44d9 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-teres-i.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-teres-i.dts
@@ -205,7 +205,7 @@ axp803: pmic@3a3 {
 		compatible = "x-powers,axp803";
 		reg = <0x3a3>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
 		wakeup-source;
 	};
 };
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index 51cc30e84e26..fd4bf90163d5 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -1215,7 +1215,7 @@ r_intc: interrupt-controller@1f00c00 {
 			compatible = "allwinner,sun50i-a64-r-intc",
 				     "allwinner,sun6i-a31-r-intc";
 			interrupt-controller;
-			#interrupt-cells = <2>;
+			#interrupt-cells = <3>;
 			reg = <0x01f00c00 0x400>;
 			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
 		};
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts
index 7c9dbde645b5..5c39f5f3f22c 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts
@@ -157,7 +157,7 @@ axp805: pmic@36 {
 		compatible = "x-powers,axp805", "x-powers,axp806";
 		reg = <0x36>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>;
 		interrupt-controller;
 		#interrupt-cells = <1>;
 		x-powers,self-working-mode;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
index 15c9dd8c4479..41aaad43b5d5 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
@@ -182,7 +182,7 @@ axp805: pmic@36 {
 		compatible = "x-powers,axp805", "x-powers,axp806";
 		reg = <0x36>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>;
 		interrupt-controller;
 		#interrupt-cells = <1>;
 		x-powers,self-working-mode;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi
index ebc120a9232f..1ee19f5fc6ab 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi
@@ -119,7 +119,7 @@ axp805: pmic@36 {
 		compatible = "x-powers,axp805", "x-powers,axp806";
 		reg = <0x36>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>;
 		interrupt-controller;
 		#interrupt-cells = <1>;
 		x-powers,self-working-mode;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
index 961732c52aa0..0b9117e986b7 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
@@ -167,7 +167,7 @@ axp805: pmic@36 {
 		compatible = "x-powers,axp805", "x-powers,axp806";
 		reg = <0x36>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>;
 		interrupt-controller;
 		#interrupt-cells = <1>;
 		x-powers,self-working-mode;
@@ -280,7 +280,7 @@ pcf8563: rtc@51 {
 		compatible = "nxp,pcf8563";
 		reg = <0x51>;
 		interrupt-parent = <&r_intc>;
-		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>;
 		#clock-cells = <0>;
 	};
 };
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index 8a62a9fbe347..d838bcc7aa60 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -923,7 +923,7 @@ r_intc: interrupt-controller@7021000 {
 			compatible = "allwinner,sun50i-h6-r-intc",
 				     "allwinner,sun6i-a31-r-intc";
 			interrupt-controller;
-			#interrupt-cells = <2>;
+			#interrupt-cells = <3>;
 			reg = <0x07021000 0x400>;
 			interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
 		};
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 10/10] arm64: dts: allwinner: Move wakeup-capable IRQs to r_intc
  2021-01-03 10:30 ` Samuel Holland
@ 2021-01-03 10:31   ` Samuel Holland
  -1 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:31 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel,
	linux-sunxi, Samuel Holland

All IRQs that can be used to wake up the system must be routed through
r_intc, so they are visible to firmware while the system is suspended.

In addition to the external NMI input, which is already routed through
r_intc, these include PIO and R_PIO (gpio-keys), the LRADC, and the RTC.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 4 ++++
 arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi  | 3 +++
 2 files changed, 7 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index fd4bf90163d5..b8697e84342e 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -644,6 +644,7 @@ ccu: clock@1c20000 {
 		pio: pinctrl@1c20800 {
 			compatible = "allwinner,sun50i-a64-pinctrl";
 			reg = <0x01c20800 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
@@ -814,6 +815,7 @@ lradc: lradc@1c21800 {
 			compatible = "allwinner,sun50i-a64-lradc",
 				     "allwinner,sun8i-a83t-r-lradc";
 			reg = <0x01c21800 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
@@ -1204,6 +1206,7 @@ rtc: rtc@1f00000 {
 			compatible = "allwinner,sun50i-a64-rtc",
 				     "allwinner,sun8i-h3-rtc";
 			reg = <0x01f00000 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
 			clock-output-names = "osc32k", "osc32k-out", "iosc";
@@ -1275,6 +1278,7 @@ r_pwm: pwm@1f03800 {
 		r_pio: pinctrl@1f02c00 {
 			compatible = "allwinner,sun50i-a64-r-pinctrl";
 			reg = <0x01f02c00 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&r_ccu CLK_APB0_PIO>, <&osc24M>, <&osc32k>;
 			clock-names = "apb", "hosc", "losc";
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index d838bcc7aa60..7587544301c3 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -294,6 +294,7 @@ pwm: pwm@300a000 {
 		pio: pinctrl@300b000 {
 			compatible = "allwinner,sun50i-h6-pinctrl";
 			reg = <0x0300b000 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
@@ -895,6 +896,7 @@ tcon_tv_out_tcon_top: endpoint@1 {
 		rtc: rtc@7000000 {
 			compatible = "allwinner,sun50i-h6-rtc";
 			reg = <0x07000000 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
 			clock-output-names = "osc32k", "osc32k-out", "iosc";
@@ -931,6 +933,7 @@ r_intc: interrupt-controller@7021000 {
 		r_pio: pinctrl@7022000 {
 			compatible = "allwinner,sun50i-h6-r-pinctrl";
 			reg = <0x07022000 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&r_ccu CLK_R_APB1>, <&osc24M>, <&rtc 0>;
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 10/10] arm64: dts: allwinner: Move wakeup-capable IRQs to r_intc
@ 2021-01-03 10:31   ` Samuel Holland
  0 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 10:31 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Rob Herring, Maxime Ripard,
	Chen-Yu Tsai, Jernej Skrabec, Russell King, Catalin Marinas,
	Will Deacon
  Cc: Ondrej Jirman, devicetree, Samuel Holland, linux-kernel,
	linux-sunxi, linux-arm-kernel

All IRQs that can be used to wake up the system must be routed through
r_intc, so they are visible to firmware while the system is suspended.

In addition to the external NMI input, which is already routed through
r_intc, these include PIO and R_PIO (gpio-keys), the LRADC, and the RTC.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 4 ++++
 arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi  | 3 +++
 2 files changed, 7 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index fd4bf90163d5..b8697e84342e 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -644,6 +644,7 @@ ccu: clock@1c20000 {
 		pio: pinctrl@1c20800 {
 			compatible = "allwinner,sun50i-a64-pinctrl";
 			reg = <0x01c20800 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
@@ -814,6 +815,7 @@ lradc: lradc@1c21800 {
 			compatible = "allwinner,sun50i-a64-lradc",
 				     "allwinner,sun8i-a83t-r-lradc";
 			reg = <0x01c21800 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
@@ -1204,6 +1206,7 @@ rtc: rtc@1f00000 {
 			compatible = "allwinner,sun50i-a64-rtc",
 				     "allwinner,sun8i-h3-rtc";
 			reg = <0x01f00000 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
 			clock-output-names = "osc32k", "osc32k-out", "iosc";
@@ -1275,6 +1278,7 @@ r_pwm: pwm@1f03800 {
 		r_pio: pinctrl@1f02c00 {
 			compatible = "allwinner,sun50i-a64-r-pinctrl";
 			reg = <0x01f02c00 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&r_ccu CLK_APB0_PIO>, <&osc24M>, <&osc32k>;
 			clock-names = "apb", "hosc", "losc";
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index d838bcc7aa60..7587544301c3 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -294,6 +294,7 @@ pwm: pwm@300a000 {
 		pio: pinctrl@300b000 {
 			compatible = "allwinner,sun50i-h6-pinctrl";
 			reg = <0x0300b000 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
@@ -895,6 +896,7 @@ tcon_tv_out_tcon_top: endpoint@1 {
 		rtc: rtc@7000000 {
 			compatible = "allwinner,sun50i-h6-rtc";
 			reg = <0x07000000 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
 			clock-output-names = "osc32k", "osc32k-out", "iosc";
@@ -931,6 +933,7 @@ r_intc: interrupt-controller@7021000 {
 		r_pio: pinctrl@7022000 {
 			compatible = "allwinner,sun50i-h6-r-pinctrl";
 			reg = <0x07022000 0x400>;
+			interrupt-parent = <&r_intc>;
 			interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&r_ccu CLK_R_APB1>, <&osc24M>, <&rtc 0>;
-- 
2.26.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 03/10] irqchip/sun6i-r: Use a stacked irqchip driver
  2021-01-03 10:30   ` Samuel Holland
@ 2021-01-03 11:27     ` Marc Zyngier
  -1 siblings, 0 replies; 44+ messages in thread
From: Marc Zyngier @ 2021-01-03 11:27 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Thomas Gleixner, Rob Herring, Maxime Ripard, Chen-Yu Tsai,
	Jernej Skrabec, Russell King, Catalin Marinas, Will Deacon,
	Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel,
	linux-sunxi

On Sun, 03 Jan 2021 10:30:54 +0000,
Samuel Holland <samuel@sholland.org> wrote:
> 
> The R_INTC in the A31 and newer sun8i/sun50i SoCs is more similar to the
> original sun4i interrupt controller than the sun7i/sun9i NMI controller.
> It is used for two distinct purposes:
>  - To control the trigger, latch, and mask for the NMI input pin
>  - To provide the interrupt input for the ARISC coprocessor
> 
> As this interrupt controller is not documented, information about it
> comes from vendor-provided firmware blobs and from experimentation.
> 
> Like the original sun4i interrupt controller, it has:
>  - A VECTOR_REG at 0x00 (configurable via the BASE_ADDR_REG at 0x04)
>  - A NMI_CTRL_REG, PENDING_REG, and ENABLE_REG as used by both the
>    sun4i and sunxi-nmi drivers
>  - A MASK_REG at 0x50
>  - A RESP_REG at 0x60
> 
> Differences from the sun4i interrupt controller appear to be:
>  - It only has one or two registers of each kind (max 32 or 64 IRQs)
>  - Multiplexing logic is added to support additional inputs
>  - There is no FIQ-related logic
>  - There is no interrupt priority logic
> 
> In order to fulfill its two purposes, this hardware block combines four
> types of IRQs. First, the NMI pin is routed to the "IRQ 0" input on this
> chip, with a trigger type controlled by the NMI_CTRL_REG. The "IRQ 0
> pending" output from this chip, if enabled, is then routed to a SPI IRQ
> input on the GIC. In other words, bit 0 of IRQ_ENABLE_REG *does* affect
> the NMI IRQ seen at the GIC.
> 
> The NMI is followed by a contiguous block of 15 "direct" (my name for
> them) IRQ inputs that are connected in parallel to both R_INTC and the
> GIC. Or in other words, these bits of IRQ_ENABLE_REG *do not* affect the
> IRQs seen at the GIC.
> 
> Following the direct IRQs are the ARISC's copy of banked IRQs for shared
> peripherals. These are not relevant to Linux. The remaining IRQs are
> connected to a multiplexer and provide access to the first (up to) 128
> SPIs from the ARISC. This range of SPIs overlaps with the direct IRQs.
> 
> Finally, the global "IRQ pending" output from R_INTC, after being masked
> by MASK_REG and RESP_REG, is connected to the "external interrupt" input
> of the ARISC CPU. This path is also irrelevant to Linux.

An ASCII-art version of this would help a lot, and would look good in
the driver code...

> 
> Because of the 1:1 correspondence between R_INTC and GIC inputs, this is
> a perfect scenario for using a stacked irqchip driver. We want to hook
> into enabling/disabling IRQs to add more features to the GIC
> (specifically to allow masking the NMI and setting its trigger type),
> but we don't need to actually handle the IRQ in this driver.
> 
> And since R_INTC is in the always-on power domain, and its output is
> connected directly in to the power management coprocessor, a stacked
> irqchip driver provides a simple way to add wakeup support to this set
> of IRQs. That is the next patch; for now, just the NMI is moved over.
> 
> To allow access to all multiplexed IRQs, this driver requires a new
> binding where the interrupt number matches the GIC interrupt number.
> (This moves the NMI number from 0 to 32 or 96, depending on the SoC.)
> For simplicity, copy the three-cell GIC binding; this disambiguates
> interrupt 0 in the old binding (the NMI) from interrupt 0 in the new
> binding (SPI 0) by the number of cells.
> 
> This commit mostly reverts commit 173bda53b340 ("irqchip/sunxi-nmi:
> Support sun6i-a31-r-intc compatible").
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  arch/arm/mach-sunxi/Kconfig     |   1 +
>  arch/arm64/Kconfig.platforms    |   1 +
>  drivers/irqchip/Makefile        |   1 +
>  drivers/irqchip/irq-sun6i-r.c   | 267 ++++++++++++++++++++++++++++++++
>  drivers/irqchip/irq-sunxi-nmi.c |  26 +---
>  5 files changed, 273 insertions(+), 23 deletions(-)
>  create mode 100644 drivers/irqchip/irq-sun6i-r.c
> 

[...]

> diff --git a/drivers/irqchip/irq-sun6i-r.c b/drivers/irqchip/irq-sun6i-r.c
> new file mode 100644
> index 000000000000..7490ade7b254
> --- /dev/null
> +++ b/drivers/irqchip/irq-sun6i-r.c
> @@ -0,0 +1,267 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +//
> +// R_INTC driver for Allwinner A31 and newer SoCs
> +//
> +
> +#include <linux/irq.h>
> +#include <linux/irqchip.h>
> +#include <linux/irqdomain.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +
> +#include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +/*
> + * The R_INTC manages between 32 and 64 IRQs, divided into four groups. Example
> + * bit numbers are for the original variant in the A31:
> + *
> + *   Bit      0: The "External NMI" input, connected in series to a GIC SPI.
> + *   Bits  1-15: "Direct" IRQs for ARISC peripherals, connected in parallel to
> + *               the GIC and mapped 1:1 to SPIs numerically following the NMI.
> + *   Bits 16-18: "Banked" IRQs for peripherals that have separate interfaces
> + *               for the ARM CPUs and ARISC. These do not map to any GIC SPI.
> + *   Bits 19-31: "Muxed" IRQs, each corresponding to a group of up to 8 SPIs.
> + *               Later variants added a second PENDING and ENABLE register to
> + *               make use of all 128 mux inputs (16 IRQ lines).
> + *
> + * Since the direct IRQs are inside the muxed IRQ range, they do not increase
> + * the number of HWIRQs needed.
> + */
> +#define SUN6I_NR_IRQS			64
> +#define SUN6I_NR_DIRECT_IRQS		16
> +#define SUN6I_NR_MUX_INPUTS		128
> +#define SUN6I_NR_HWIRQS			SUN6I_NR_MUX_INPUTS
> +
> +#define SUN6I_NMI_CTRL			(0x0c)
> +#define SUN6I_IRQ_PENDING(n)		(0x10 + 4 * (n))
> +#define SUN6I_IRQ_ENABLE(n)		(0x40 + 4 * (n))
> +#define SUN6I_MUX_ENABLE(n)		(0xc0 + 4 * (n))
> +
> +#define SUN6I_NMI_IRQ_BIT		BIT(0)
> +
> +static void __iomem *base;
> +static irq_hw_number_t nmi_hwirq;
> +static u32 nmi_type;
> +
> +static struct irq_chip sun6i_r_intc_edge_chip;
> +static struct irq_chip sun6i_r_intc_level_chip;
> +
> +static void sun6i_r_intc_nmi_ack(void)
> +{
> +	/*
> +	 * The NMI channel has a latch separate from its trigger type.
> +	 * This latch must be cleared to clear the signal to the GIC.
> +	 */
> +	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_PENDING(0));
> +}
> +
> +static void sun6i_r_intc_irq_mask(struct irq_data *data)
> +{
> +	if (data->hwirq == nmi_hwirq)
> +		sun6i_r_intc_nmi_ack();

I'm a bit worried by this. I can see it working with level interrupts
(you can clear the input, and if the interrupt is asserted, it will
fire again), but I'm worried that it will simply result in lost
interrupts for edge signalling.

It also begs the question: why would you want to clear the signal to
the GIC on mask (or unmask)? The expectations are that a pending
interrupt is preserved across a mask/unmask sequence.

> +
> +	irq_chip_mask_parent(data);
> +}
> +
> +static void sun6i_r_intc_irq_unmask(struct irq_data *data)
> +{
> +	if (data->hwirq == nmi_hwirq)
> +		sun6i_r_intc_nmi_ack();
> +
> +	irq_chip_unmask_parent(data);
> +}
> +
> +static int sun6i_r_intc_irq_set_type(struct irq_data *data, unsigned int type)
> +{
> +	/*
> +	 * The GIC input labeled "External NMI" connects to bit 0 of the R_INTC
> +	 * PENDING register, not to the pin directly. So the trigger type of the
> +	 * GIC input does not depend on the trigger type of the NMI pin itself.
> +	 *
> +	 * Only the NMI channel is routed through this interrupt controller on
> +	 * its way to the GIC. Other IRQs are routed to the GIC and R_INTC in
> +	 * parallel; they must have a trigger type appropriate for the GIC.
> +	 */
> +	if (data->hwirq == nmi_hwirq) {
> +		struct irq_chip *chip;
> +		u32 nmi_src_type;
> +
> +		switch (type) {
> +		case IRQ_TYPE_LEVEL_LOW:
> +			chip = &sun6i_r_intc_level_chip;
> +			nmi_src_type = 0;

Please add symbolic names for these types.

> +			break;
> +		case IRQ_TYPE_EDGE_FALLING:
> +			chip = &sun6i_r_intc_edge_chip;
> +			nmi_src_type = 1;
> +			break;
> +		case IRQ_TYPE_LEVEL_HIGH:
> +			chip = &sun6i_r_intc_level_chip;
> +			nmi_src_type = 2;
> +			break;
> +		case IRQ_TYPE_EDGE_RISING:
> +			chip = &sun6i_r_intc_edge_chip;
> +			nmi_src_type = 3;
> +			break;
> +		default:
> +			pr_err("%pOF: invalid trigger type %d for IRQ %d\n",
> +			       irq_domain_get_of_node(data->domain), type,
> +			       data->irq);

A failing set_type already triggers a kernel message.

> +			return -EBADR;

That's a pretty odd error. I see it used in 3 drivers (including the
one this driver replaces), but the canonical error code is -EINVAL.

> +		}
> +
> +		irq_set_chip_handler_name_locked(data, chip,
> +						 handle_fasteoi_irq, NULL);
> +
> +		writel_relaxed(nmi_src_type, base + SUN6I_NMI_CTRL);
> +
> +		/*
> +		 * Use the trigger type from the OF node for the NMI's
> +		 * R_INTC to GIC connection.
> +		 */
> +		type = nmi_type;

This looks wrong. The GIC only supports level-high and edge-rising, so
half of the possible settings will result in an error. I assume the
R_INTC has an inverter controlled by nmi_src_type, and only outputs
something the GIC can grok.

> +	}
> +
> +	return irq_chip_set_type_parent(data, type);
> +}
> +
> +static struct irq_chip sun6i_r_intc_edge_chip = {
> +	.name			= "sun6i-r-intc",
> +	.irq_mask		= sun6i_r_intc_irq_mask,
> +	.irq_unmask		= irq_chip_unmask_parent,
> +	.irq_eoi		= irq_chip_eoi_parent,
> +	.irq_set_affinity	= irq_chip_set_affinity_parent,
> +	.irq_set_type		= sun6i_r_intc_irq_set_type,
> +	.irq_get_irqchip_state	= irq_chip_get_parent_state,
> +	.irq_set_irqchip_state	= irq_chip_set_parent_state,
> +	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
> +	.flags			= IRQCHIP_SET_TYPE_MASKED,
> +};
> +
> +static struct irq_chip sun6i_r_intc_level_chip = {
> +	.name			= "sun6i-r-intc",
> +	.irq_mask		= irq_chip_mask_parent,
> +	.irq_unmask		= sun6i_r_intc_irq_unmask,
> +	.irq_eoi		= irq_chip_eoi_parent,
> +	.irq_set_affinity	= irq_chip_set_affinity_parent,
> +	.irq_set_type		= sun6i_r_intc_irq_set_type,
> +	.irq_get_irqchip_state	= irq_chip_get_parent_state,
> +	.irq_set_irqchip_state	= irq_chip_set_parent_state,
> +	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
> +	.flags			= IRQCHIP_SET_TYPE_MASKED,
> +};
> +
> +static int sun6i_r_intc_domain_translate(struct irq_domain *domain,
> +					 struct irq_fwspec *fwspec,
> +					 unsigned long *hwirq,
> +					 unsigned int *type)
> +{
> +	/* Accept the old two-cell binding for the NMI only. */
> +	if (fwspec->param_count == 2 && fwspec->param[0] == 0) {
> +		*hwirq = nmi_hwirq;
> +		*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
> +		return 0;
> +	}
> +
> +	/* Otherwise this binding should match the GIC SPI binding. */
> +	if (fwspec->param_count < 3)
> +		return -EINVAL;
> +	if (fwspec->param[0] != GIC_SPI)
> +		return -EINVAL;
> +
> +	*hwirq = fwspec->param[1];
> +	*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
> +
> +	return 0;
> +}
> +
> +static int sun6i_r_intc_domain_alloc(struct irq_domain *domain,
> +				     unsigned int virq,
> +				     unsigned int nr_irqs, void *arg)
> +{
> +	struct irq_fwspec *fwspec = arg;
> +	struct irq_fwspec gic_fwspec;
> +	unsigned long hwirq;
> +	unsigned int type;
> +	int i, ret;
> +
> +	ret = sun6i_r_intc_domain_translate(domain, fwspec, &hwirq, &type);
> +	if (ret)
> +		return ret;
> +	if (hwirq + nr_irqs > SUN6I_NR_HWIRQS)
> +		return -EINVAL;
> +
> +	/* Construct a GIC-compatible fwspec from this fwspec. */
> +	gic_fwspec = (struct irq_fwspec) {
> +		.fwnode      = domain->parent->fwnode,
> +		.param_count = 3,
> +		.param       = { GIC_SPI, hwirq, type },
> +	};
> +
> +	for (i = 0; i < nr_irqs; ++i)
> +		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
> +					      &sun6i_r_intc_level_chip, NULL);

Unconditionally level, without looking at the requested type?

> +
> +	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_fwspec);
> +}
> +
> +static const struct irq_domain_ops sun6i_r_intc_domain_ops = {
> +	.translate	= sun6i_r_intc_domain_translate,
> +	.alloc		= sun6i_r_intc_domain_alloc,
> +	.free		= irq_domain_free_irqs_common,
> +};
> +
> +static void sun6i_r_intc_resume(void)
> +{
> +	int i;
> +
> +	/* Only the NMI is relevant during normal operation. */
> +	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_ENABLE(0));
> +	for (i = 1; i < BITS_TO_U32(SUN6I_NR_IRQS); ++i)
> +		writel_relaxed(0, base + SUN6I_IRQ_ENABLE(i));

If only the NMI is relevant, why are the other interrupts enabled?
Shouldn't this be moved to the following patch (I presume this is
wake-up related...).

> +}
> +
> +static int __init sun6i_r_intc_init(struct device_node *node,
> +				    struct device_node *parent)
> +{
> +	struct irq_domain *domain, *parent_domain;
> +	struct of_phandle_args parent_irq;
> +	int ret;
> +
> +	/* Extract the NMI's R_INTC to GIC mapping from the OF node. */
> +	ret = of_irq_parse_one(node, 0, &parent_irq);
> +	if (ret)
> +		return ret;
> +	if (parent_irq.args_count < 3 || parent_irq.args[0] != GIC_SPI)
> +		return -EINVAL;
> +	nmi_hwirq = parent_irq.args[1];
> +	nmi_type = parent_irq.args[2];

This looks a lot like the translate callback.

> +
> +	parent_domain = irq_find_host(parent);
> +	if (!parent_domain) {
> +		pr_err("%pOF: Failed to obtain parent domain\n", node);
> +		return -ENXIO;
> +	}
> +
> +	base = of_io_request_and_map(node, 0, NULL);
> +	if (IS_ERR(base)) {
> +		pr_err("%pOF: Failed to map MMIO region\n", node);
> +		return PTR_ERR(base);
> +	}
> +
> +	sun6i_r_intc_nmi_ack();
> +	sun6i_r_intc_resume();
> +
> +	domain = irq_domain_add_hierarchy(parent_domain, 0,
> +					  SUN6I_NR_HWIRQS, node,
> +					  &sun6i_r_intc_domain_ops, NULL);
> +	if (!domain) {
> +		pr_err("%pOF: Failed to allocate domain\n", node);
> +		iounmap(base);
> +		return -ENOMEM;
> +	}
> +
> +	return 0;
> +}
> +IRQCHIP_DECLARE(sun6i_r_intc, "allwinner,sun6i-a31-r-intc", sun6i_r_intc_init);

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 03/10] irqchip/sun6i-r: Use a stacked irqchip driver
@ 2021-01-03 11:27     ` Marc Zyngier
  0 siblings, 0 replies; 44+ messages in thread
From: Marc Zyngier @ 2021-01-03 11:27 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, devicetree, Jernej Skrabec, Catalin Marinas,
	linux-sunxi, Russell King, Maxime Ripard, linux-kernel,
	Chen-Yu Tsai, Rob Herring, Thomas Gleixner, Will Deacon,
	linux-arm-kernel

On Sun, 03 Jan 2021 10:30:54 +0000,
Samuel Holland <samuel@sholland.org> wrote:
> 
> The R_INTC in the A31 and newer sun8i/sun50i SoCs is more similar to the
> original sun4i interrupt controller than the sun7i/sun9i NMI controller.
> It is used for two distinct purposes:
>  - To control the trigger, latch, and mask for the NMI input pin
>  - To provide the interrupt input for the ARISC coprocessor
> 
> As this interrupt controller is not documented, information about it
> comes from vendor-provided firmware blobs and from experimentation.
> 
> Like the original sun4i interrupt controller, it has:
>  - A VECTOR_REG at 0x00 (configurable via the BASE_ADDR_REG at 0x04)
>  - A NMI_CTRL_REG, PENDING_REG, and ENABLE_REG as used by both the
>    sun4i and sunxi-nmi drivers
>  - A MASK_REG at 0x50
>  - A RESP_REG at 0x60
> 
> Differences from the sun4i interrupt controller appear to be:
>  - It only has one or two registers of each kind (max 32 or 64 IRQs)
>  - Multiplexing logic is added to support additional inputs
>  - There is no FIQ-related logic
>  - There is no interrupt priority logic
> 
> In order to fulfill its two purposes, this hardware block combines four
> types of IRQs. First, the NMI pin is routed to the "IRQ 0" input on this
> chip, with a trigger type controlled by the NMI_CTRL_REG. The "IRQ 0
> pending" output from this chip, if enabled, is then routed to a SPI IRQ
> input on the GIC. In other words, bit 0 of IRQ_ENABLE_REG *does* affect
> the NMI IRQ seen at the GIC.
> 
> The NMI is followed by a contiguous block of 15 "direct" (my name for
> them) IRQ inputs that are connected in parallel to both R_INTC and the
> GIC. Or in other words, these bits of IRQ_ENABLE_REG *do not* affect the
> IRQs seen at the GIC.
> 
> Following the direct IRQs are the ARISC's copy of banked IRQs for shared
> peripherals. These are not relevant to Linux. The remaining IRQs are
> connected to a multiplexer and provide access to the first (up to) 128
> SPIs from the ARISC. This range of SPIs overlaps with the direct IRQs.
> 
> Finally, the global "IRQ pending" output from R_INTC, after being masked
> by MASK_REG and RESP_REG, is connected to the "external interrupt" input
> of the ARISC CPU. This path is also irrelevant to Linux.

An ASCII-art version of this would help a lot, and would look good in
the driver code...

> 
> Because of the 1:1 correspondence between R_INTC and GIC inputs, this is
> a perfect scenario for using a stacked irqchip driver. We want to hook
> into enabling/disabling IRQs to add more features to the GIC
> (specifically to allow masking the NMI and setting its trigger type),
> but we don't need to actually handle the IRQ in this driver.
> 
> And since R_INTC is in the always-on power domain, and its output is
> connected directly in to the power management coprocessor, a stacked
> irqchip driver provides a simple way to add wakeup support to this set
> of IRQs. That is the next patch; for now, just the NMI is moved over.
> 
> To allow access to all multiplexed IRQs, this driver requires a new
> binding where the interrupt number matches the GIC interrupt number.
> (This moves the NMI number from 0 to 32 or 96, depending on the SoC.)
> For simplicity, copy the three-cell GIC binding; this disambiguates
> interrupt 0 in the old binding (the NMI) from interrupt 0 in the new
> binding (SPI 0) by the number of cells.
> 
> This commit mostly reverts commit 173bda53b340 ("irqchip/sunxi-nmi:
> Support sun6i-a31-r-intc compatible").
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  arch/arm/mach-sunxi/Kconfig     |   1 +
>  arch/arm64/Kconfig.platforms    |   1 +
>  drivers/irqchip/Makefile        |   1 +
>  drivers/irqchip/irq-sun6i-r.c   | 267 ++++++++++++++++++++++++++++++++
>  drivers/irqchip/irq-sunxi-nmi.c |  26 +---
>  5 files changed, 273 insertions(+), 23 deletions(-)
>  create mode 100644 drivers/irqchip/irq-sun6i-r.c
> 

[...]

> diff --git a/drivers/irqchip/irq-sun6i-r.c b/drivers/irqchip/irq-sun6i-r.c
> new file mode 100644
> index 000000000000..7490ade7b254
> --- /dev/null
> +++ b/drivers/irqchip/irq-sun6i-r.c
> @@ -0,0 +1,267 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +//
> +// R_INTC driver for Allwinner A31 and newer SoCs
> +//
> +
> +#include <linux/irq.h>
> +#include <linux/irqchip.h>
> +#include <linux/irqdomain.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +
> +#include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +/*
> + * The R_INTC manages between 32 and 64 IRQs, divided into four groups. Example
> + * bit numbers are for the original variant in the A31:
> + *
> + *   Bit      0: The "External NMI" input, connected in series to a GIC SPI.
> + *   Bits  1-15: "Direct" IRQs for ARISC peripherals, connected in parallel to
> + *               the GIC and mapped 1:1 to SPIs numerically following the NMI.
> + *   Bits 16-18: "Banked" IRQs for peripherals that have separate interfaces
> + *               for the ARM CPUs and ARISC. These do not map to any GIC SPI.
> + *   Bits 19-31: "Muxed" IRQs, each corresponding to a group of up to 8 SPIs.
> + *               Later variants added a second PENDING and ENABLE register to
> + *               make use of all 128 mux inputs (16 IRQ lines).
> + *
> + * Since the direct IRQs are inside the muxed IRQ range, they do not increase
> + * the number of HWIRQs needed.
> + */
> +#define SUN6I_NR_IRQS			64
> +#define SUN6I_NR_DIRECT_IRQS		16
> +#define SUN6I_NR_MUX_INPUTS		128
> +#define SUN6I_NR_HWIRQS			SUN6I_NR_MUX_INPUTS
> +
> +#define SUN6I_NMI_CTRL			(0x0c)
> +#define SUN6I_IRQ_PENDING(n)		(0x10 + 4 * (n))
> +#define SUN6I_IRQ_ENABLE(n)		(0x40 + 4 * (n))
> +#define SUN6I_MUX_ENABLE(n)		(0xc0 + 4 * (n))
> +
> +#define SUN6I_NMI_IRQ_BIT		BIT(0)
> +
> +static void __iomem *base;
> +static irq_hw_number_t nmi_hwirq;
> +static u32 nmi_type;
> +
> +static struct irq_chip sun6i_r_intc_edge_chip;
> +static struct irq_chip sun6i_r_intc_level_chip;
> +
> +static void sun6i_r_intc_nmi_ack(void)
> +{
> +	/*
> +	 * The NMI channel has a latch separate from its trigger type.
> +	 * This latch must be cleared to clear the signal to the GIC.
> +	 */
> +	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_PENDING(0));
> +}
> +
> +static void sun6i_r_intc_irq_mask(struct irq_data *data)
> +{
> +	if (data->hwirq == nmi_hwirq)
> +		sun6i_r_intc_nmi_ack();

I'm a bit worried by this. I can see it working with level interrupts
(you can clear the input, and if the interrupt is asserted, it will
fire again), but I'm worried that it will simply result in lost
interrupts for edge signalling.

It also begs the question: why would you want to clear the signal to
the GIC on mask (or unmask)? The expectations are that a pending
interrupt is preserved across a mask/unmask sequence.

> +
> +	irq_chip_mask_parent(data);
> +}
> +
> +static void sun6i_r_intc_irq_unmask(struct irq_data *data)
> +{
> +	if (data->hwirq == nmi_hwirq)
> +		sun6i_r_intc_nmi_ack();
> +
> +	irq_chip_unmask_parent(data);
> +}
> +
> +static int sun6i_r_intc_irq_set_type(struct irq_data *data, unsigned int type)
> +{
> +	/*
> +	 * The GIC input labeled "External NMI" connects to bit 0 of the R_INTC
> +	 * PENDING register, not to the pin directly. So the trigger type of the
> +	 * GIC input does not depend on the trigger type of the NMI pin itself.
> +	 *
> +	 * Only the NMI channel is routed through this interrupt controller on
> +	 * its way to the GIC. Other IRQs are routed to the GIC and R_INTC in
> +	 * parallel; they must have a trigger type appropriate for the GIC.
> +	 */
> +	if (data->hwirq == nmi_hwirq) {
> +		struct irq_chip *chip;
> +		u32 nmi_src_type;
> +
> +		switch (type) {
> +		case IRQ_TYPE_LEVEL_LOW:
> +			chip = &sun6i_r_intc_level_chip;
> +			nmi_src_type = 0;

Please add symbolic names for these types.

> +			break;
> +		case IRQ_TYPE_EDGE_FALLING:
> +			chip = &sun6i_r_intc_edge_chip;
> +			nmi_src_type = 1;
> +			break;
> +		case IRQ_TYPE_LEVEL_HIGH:
> +			chip = &sun6i_r_intc_level_chip;
> +			nmi_src_type = 2;
> +			break;
> +		case IRQ_TYPE_EDGE_RISING:
> +			chip = &sun6i_r_intc_edge_chip;
> +			nmi_src_type = 3;
> +			break;
> +		default:
> +			pr_err("%pOF: invalid trigger type %d for IRQ %d\n",
> +			       irq_domain_get_of_node(data->domain), type,
> +			       data->irq);

A failing set_type already triggers a kernel message.

> +			return -EBADR;

That's a pretty odd error. I see it used in 3 drivers (including the
one this driver replaces), but the canonical error code is -EINVAL.

> +		}
> +
> +		irq_set_chip_handler_name_locked(data, chip,
> +						 handle_fasteoi_irq, NULL);
> +
> +		writel_relaxed(nmi_src_type, base + SUN6I_NMI_CTRL);
> +
> +		/*
> +		 * Use the trigger type from the OF node for the NMI's
> +		 * R_INTC to GIC connection.
> +		 */
> +		type = nmi_type;

This looks wrong. The GIC only supports level-high and edge-rising, so
half of the possible settings will result in an error. I assume the
R_INTC has an inverter controlled by nmi_src_type, and only outputs
something the GIC can grok.

> +	}
> +
> +	return irq_chip_set_type_parent(data, type);
> +}
> +
> +static struct irq_chip sun6i_r_intc_edge_chip = {
> +	.name			= "sun6i-r-intc",
> +	.irq_mask		= sun6i_r_intc_irq_mask,
> +	.irq_unmask		= irq_chip_unmask_parent,
> +	.irq_eoi		= irq_chip_eoi_parent,
> +	.irq_set_affinity	= irq_chip_set_affinity_parent,
> +	.irq_set_type		= sun6i_r_intc_irq_set_type,
> +	.irq_get_irqchip_state	= irq_chip_get_parent_state,
> +	.irq_set_irqchip_state	= irq_chip_set_parent_state,
> +	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
> +	.flags			= IRQCHIP_SET_TYPE_MASKED,
> +};
> +
> +static struct irq_chip sun6i_r_intc_level_chip = {
> +	.name			= "sun6i-r-intc",
> +	.irq_mask		= irq_chip_mask_parent,
> +	.irq_unmask		= sun6i_r_intc_irq_unmask,
> +	.irq_eoi		= irq_chip_eoi_parent,
> +	.irq_set_affinity	= irq_chip_set_affinity_parent,
> +	.irq_set_type		= sun6i_r_intc_irq_set_type,
> +	.irq_get_irqchip_state	= irq_chip_get_parent_state,
> +	.irq_set_irqchip_state	= irq_chip_set_parent_state,
> +	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
> +	.flags			= IRQCHIP_SET_TYPE_MASKED,
> +};
> +
> +static int sun6i_r_intc_domain_translate(struct irq_domain *domain,
> +					 struct irq_fwspec *fwspec,
> +					 unsigned long *hwirq,
> +					 unsigned int *type)
> +{
> +	/* Accept the old two-cell binding for the NMI only. */
> +	if (fwspec->param_count == 2 && fwspec->param[0] == 0) {
> +		*hwirq = nmi_hwirq;
> +		*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
> +		return 0;
> +	}
> +
> +	/* Otherwise this binding should match the GIC SPI binding. */
> +	if (fwspec->param_count < 3)
> +		return -EINVAL;
> +	if (fwspec->param[0] != GIC_SPI)
> +		return -EINVAL;
> +
> +	*hwirq = fwspec->param[1];
> +	*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
> +
> +	return 0;
> +}
> +
> +static int sun6i_r_intc_domain_alloc(struct irq_domain *domain,
> +				     unsigned int virq,
> +				     unsigned int nr_irqs, void *arg)
> +{
> +	struct irq_fwspec *fwspec = arg;
> +	struct irq_fwspec gic_fwspec;
> +	unsigned long hwirq;
> +	unsigned int type;
> +	int i, ret;
> +
> +	ret = sun6i_r_intc_domain_translate(domain, fwspec, &hwirq, &type);
> +	if (ret)
> +		return ret;
> +	if (hwirq + nr_irqs > SUN6I_NR_HWIRQS)
> +		return -EINVAL;
> +
> +	/* Construct a GIC-compatible fwspec from this fwspec. */
> +	gic_fwspec = (struct irq_fwspec) {
> +		.fwnode      = domain->parent->fwnode,
> +		.param_count = 3,
> +		.param       = { GIC_SPI, hwirq, type },
> +	};
> +
> +	for (i = 0; i < nr_irqs; ++i)
> +		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
> +					      &sun6i_r_intc_level_chip, NULL);

Unconditionally level, without looking at the requested type?

> +
> +	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_fwspec);
> +}
> +
> +static const struct irq_domain_ops sun6i_r_intc_domain_ops = {
> +	.translate	= sun6i_r_intc_domain_translate,
> +	.alloc		= sun6i_r_intc_domain_alloc,
> +	.free		= irq_domain_free_irqs_common,
> +};
> +
> +static void sun6i_r_intc_resume(void)
> +{
> +	int i;
> +
> +	/* Only the NMI is relevant during normal operation. */
> +	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_ENABLE(0));
> +	for (i = 1; i < BITS_TO_U32(SUN6I_NR_IRQS); ++i)
> +		writel_relaxed(0, base + SUN6I_IRQ_ENABLE(i));

If only the NMI is relevant, why are the other interrupts enabled?
Shouldn't this be moved to the following patch (I presume this is
wake-up related...).

> +}
> +
> +static int __init sun6i_r_intc_init(struct device_node *node,
> +				    struct device_node *parent)
> +{
> +	struct irq_domain *domain, *parent_domain;
> +	struct of_phandle_args parent_irq;
> +	int ret;
> +
> +	/* Extract the NMI's R_INTC to GIC mapping from the OF node. */
> +	ret = of_irq_parse_one(node, 0, &parent_irq);
> +	if (ret)
> +		return ret;
> +	if (parent_irq.args_count < 3 || parent_irq.args[0] != GIC_SPI)
> +		return -EINVAL;
> +	nmi_hwirq = parent_irq.args[1];
> +	nmi_type = parent_irq.args[2];

This looks a lot like the translate callback.

> +
> +	parent_domain = irq_find_host(parent);
> +	if (!parent_domain) {
> +		pr_err("%pOF: Failed to obtain parent domain\n", node);
> +		return -ENXIO;
> +	}
> +
> +	base = of_io_request_and_map(node, 0, NULL);
> +	if (IS_ERR(base)) {
> +		pr_err("%pOF: Failed to map MMIO region\n", node);
> +		return PTR_ERR(base);
> +	}
> +
> +	sun6i_r_intc_nmi_ack();
> +	sun6i_r_intc_resume();
> +
> +	domain = irq_domain_add_hierarchy(parent_domain, 0,
> +					  SUN6I_NR_HWIRQS, node,
> +					  &sun6i_r_intc_domain_ops, NULL);
> +	if (!domain) {
> +		pr_err("%pOF: Failed to allocate domain\n", node);
> +		iounmap(base);
> +		return -ENOMEM;
> +	}
> +
> +	return 0;
> +}
> +IRQCHIP_DECLARE(sun6i_r_intc, "allwinner,sun6i-a31-r-intc", sun6i_r_intc_init);

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 03/10] irqchip/sun6i-r: Use a stacked irqchip driver
  2021-01-03 11:27     ` Marc Zyngier
@ 2021-01-03 12:08       ` Samuel Holland
  -1 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 12:08 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Thomas Gleixner, Rob Herring, Maxime Ripard, Chen-Yu Tsai,
	Jernej Skrabec, Russell King, Catalin Marinas, Will Deacon,
	Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel,
	linux-sunxi

On 1/3/21 5:27 AM, Marc Zyngier wrote:
> On Sun, 03 Jan 2021 10:30:54 +0000,
> Samuel Holland <samuel@sholland.org> wrote:
>>
>> The R_INTC in the A31 and newer sun8i/sun50i SoCs is more similar to the
>> original sun4i interrupt controller than the sun7i/sun9i NMI controller.
>> It is used for two distinct purposes:
>>  - To control the trigger, latch, and mask for the NMI input pin
>>  - To provide the interrupt input for the ARISC coprocessor
>>
>> As this interrupt controller is not documented, information about it
>> comes from vendor-provided firmware blobs and from experimentation.
>>
>> Like the original sun4i interrupt controller, it has:
>>  - A VECTOR_REG at 0x00 (configurable via the BASE_ADDR_REG at 0x04)
>>  - A NMI_CTRL_REG, PENDING_REG, and ENABLE_REG as used by both the
>>    sun4i and sunxi-nmi drivers
>>  - A MASK_REG at 0x50
>>  - A RESP_REG at 0x60
>>
>> Differences from the sun4i interrupt controller appear to be:
>>  - It only has one or two registers of each kind (max 32 or 64 IRQs)
>>  - Multiplexing logic is added to support additional inputs
>>  - There is no FIQ-related logic
>>  - There is no interrupt priority logic
>>
>> In order to fulfill its two purposes, this hardware block combines four
>> types of IRQs. First, the NMI pin is routed to the "IRQ 0" input on this
>> chip, with a trigger type controlled by the NMI_CTRL_REG. The "IRQ 0
>> pending" output from this chip, if enabled, is then routed to a SPI IRQ
>> input on the GIC. In other words, bit 0 of IRQ_ENABLE_REG *does* affect
>> the NMI IRQ seen at the GIC.
>>
>> The NMI is followed by a contiguous block of 15 "direct" (my name for
>> them) IRQ inputs that are connected in parallel to both R_INTC and the
>> GIC. Or in other words, these bits of IRQ_ENABLE_REG *do not* affect the
>> IRQs seen at the GIC.
>>
>> Following the direct IRQs are the ARISC's copy of banked IRQs for shared
>> peripherals. These are not relevant to Linux. The remaining IRQs are
>> connected to a multiplexer and provide access to the first (up to) 128
>> SPIs from the ARISC. This range of SPIs overlaps with the direct IRQs.
>>
>> Finally, the global "IRQ pending" output from R_INTC, after being masked
>> by MASK_REG and RESP_REG, is connected to the "external interrupt" input
>> of the ARISC CPU. This path is also irrelevant to Linux.
> 
> An ASCII-art version of this would help a lot, and would look good in
> the driver code...

There is this diagram which I forgot to include in the cover letter:

  https://linux-sunxi.org/images/5/5c/R_INTC.png

I can try to come up with some ASCII art.

>> Because of the 1:1 correspondence between R_INTC and GIC inputs, this is
>> a perfect scenario for using a stacked irqchip driver. We want to hook
>> into enabling/disabling IRQs to add more features to the GIC
>> (specifically to allow masking the NMI and setting its trigger type),
>> but we don't need to actually handle the IRQ in this driver.
>>
>> And since R_INTC is in the always-on power domain, and its output is
>> connected directly in to the power management coprocessor, a stacked
>> irqchip driver provides a simple way to add wakeup support to this set
>> of IRQs. That is the next patch; for now, just the NMI is moved over.
>>
>> To allow access to all multiplexed IRQs, this driver requires a new
>> binding where the interrupt number matches the GIC interrupt number.
>> (This moves the NMI number from 0 to 32 or 96, depending on the SoC.)
>> For simplicity, copy the three-cell GIC binding; this disambiguates
>> interrupt 0 in the old binding (the NMI) from interrupt 0 in the new
>> binding (SPI 0) by the number of cells.
>>
>> This commit mostly reverts commit 173bda53b340 ("irqchip/sunxi-nmi:
>> Support sun6i-a31-r-intc compatible").
>>
>> Signed-off-by: Samuel Holland <samuel@sholland.org>
>> ---
>>  arch/arm/mach-sunxi/Kconfig     |   1 +
>>  arch/arm64/Kconfig.platforms    |   1 +
>>  drivers/irqchip/Makefile        |   1 +
>>  drivers/irqchip/irq-sun6i-r.c   | 267 ++++++++++++++++++++++++++++++++
>>  drivers/irqchip/irq-sunxi-nmi.c |  26 +---
>>  5 files changed, 273 insertions(+), 23 deletions(-)
>>  create mode 100644 drivers/irqchip/irq-sun6i-r.c
>>
> 
> [...]
> 
>> diff --git a/drivers/irqchip/irq-sun6i-r.c b/drivers/irqchip/irq-sun6i-r.c
>> new file mode 100644
>> index 000000000000..7490ade7b254
>> --- /dev/null
>> +++ b/drivers/irqchip/irq-sun6i-r.c
>> @@ -0,0 +1,267 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +//
>> +// R_INTC driver for Allwinner A31 and newer SoCs
>> +//
>> +
>> +#include <linux/irq.h>
>> +#include <linux/irqchip.h>
>> +#include <linux/irqdomain.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_irq.h>
>> +
>> +#include <dt-bindings/interrupt-controller/arm-gic.h>
>> +
>> +/*
>> + * The R_INTC manages between 32 and 64 IRQs, divided into four groups. Example
>> + * bit numbers are for the original variant in the A31:
>> + *
>> + *   Bit      0: The "External NMI" input, connected in series to a GIC SPI.
>> + *   Bits  1-15: "Direct" IRQs for ARISC peripherals, connected in parallel to
>> + *               the GIC and mapped 1:1 to SPIs numerically following the NMI.
>> + *   Bits 16-18: "Banked" IRQs for peripherals that have separate interfaces
>> + *               for the ARM CPUs and ARISC. These do not map to any GIC SPI.
>> + *   Bits 19-31: "Muxed" IRQs, each corresponding to a group of up to 8 SPIs.
>> + *               Later variants added a second PENDING and ENABLE register to
>> + *               make use of all 128 mux inputs (16 IRQ lines).
>> + *
>> + * Since the direct IRQs are inside the muxed IRQ range, they do not increase
>> + * the number of HWIRQs needed.
>> + */
>> +#define SUN6I_NR_IRQS			64
>> +#define SUN6I_NR_DIRECT_IRQS		16
>> +#define SUN6I_NR_MUX_INPUTS		128
>> +#define SUN6I_NR_HWIRQS			SUN6I_NR_MUX_INPUTS
>> +
>> +#define SUN6I_NMI_CTRL			(0x0c)
>> +#define SUN6I_IRQ_PENDING(n)		(0x10 + 4 * (n))
>> +#define SUN6I_IRQ_ENABLE(n)		(0x40 + 4 * (n))
>> +#define SUN6I_MUX_ENABLE(n)		(0xc0 + 4 * (n))
>> +
>> +#define SUN6I_NMI_IRQ_BIT		BIT(0)
>> +
>> +static void __iomem *base;
>> +static irq_hw_number_t nmi_hwirq;
>> +static u32 nmi_type;
>> +
>> +static struct irq_chip sun6i_r_intc_edge_chip;
>> +static struct irq_chip sun6i_r_intc_level_chip;
>> +
>> +static void sun6i_r_intc_nmi_ack(void)
>> +{
>> +	/*
>> +	 * The NMI channel has a latch separate from its trigger type.
>> +	 * This latch must be cleared to clear the signal to the GIC.
>> +	 */
>> +	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_PENDING(0));
>> +}
>> +
>> +static void sun6i_r_intc_irq_mask(struct irq_data *data)
>> +{
>> +	if (data->hwirq == nmi_hwirq)
>> +		sun6i_r_intc_nmi_ack();
> 
> I'm a bit worried by this. I can see it working with level interrupts
> (you can clear the input, and if the interrupt is asserted, it will
> fire again), but I'm worried that it will simply result in lost
> interrupts for edge signalling.

For edge interrupts, don't you want to ack as early as possible, before the
handler clears the source of the interrupt? That way if a second interrupt comes
in while you're handling the first one, you don't ack the second one without
handling it?

> It also begs the question: why would you want to clear the signal to
> the GIC on mask (or unmask)? The expectations are that a pending
> interrupt is preserved across a mask/unmask sequence.

I hadn't thought about anything masking the IRQ outside of the handler; but
you're right, this breaks that case. I'm trying to work within the constraints
of stacking the GIC driver, which assumes handle_fasteoi_irq, so it sounds like
I should switch back to handle_fasteoi_ack_irq and use .irq_ack. Or based on
your previous paragraph, maybe I'm missing some other consideration?

>> +
>> +	irq_chip_mask_parent(data);
>> +}
>> +
>> +static void sun6i_r_intc_irq_unmask(struct irq_data *data)
>> +{
>> +	if (data->hwirq == nmi_hwirq)
>> +		sun6i_r_intc_nmi_ack();
>> +
>> +	irq_chip_unmask_parent(data);
>> +}
>> +
>> +static int sun6i_r_intc_irq_set_type(struct irq_data *data, unsigned int type)
>> +{
>> +	/*
>> +	 * The GIC input labeled "External NMI" connects to bit 0 of the R_INTC
>> +	 * PENDING register, not to the pin directly. So the trigger type of the
>> +	 * GIC input does not depend on the trigger type of the NMI pin itself.
>> +	 *
>> +	 * Only the NMI channel is routed through this interrupt controller on
>> +	 * its way to the GIC. Other IRQs are routed to the GIC and R_INTC in
>> +	 * parallel; they must have a trigger type appropriate for the GIC.
>> +	 */
>> +	if (data->hwirq == nmi_hwirq) {
>> +		struct irq_chip *chip;
>> +		u32 nmi_src_type;
>> +
>> +		switch (type) {
>> +		case IRQ_TYPE_LEVEL_LOW:
>> +			chip = &sun6i_r_intc_level_chip;
>> +			nmi_src_type = 0;
> 
> Please add symbolic names for these types.

I removed them based on your previous comment:

https://lkml.org/lkml/2020/1/20/278
> It is unusual to use an enum for values that get directly programmed into the HW.

Do you want them to be specifically #defines?

>> +			break;
>> +		case IRQ_TYPE_EDGE_FALLING:
>> +			chip = &sun6i_r_intc_edge_chip;
>> +			nmi_src_type = 1;
>> +			break;
>> +		case IRQ_TYPE_LEVEL_HIGH:
>> +			chip = &sun6i_r_intc_level_chip;
>> +			nmi_src_type = 2;
>> +			break;
>> +		case IRQ_TYPE_EDGE_RISING:
>> +			chip = &sun6i_r_intc_edge_chip;
>> +			nmi_src_type = 3;
>> +			break;
>> +		default:
>> +			pr_err("%pOF: invalid trigger type %d for IRQ %d\n",
>> +			       irq_domain_get_of_node(data->domain), type,
>> +			       data->irq);
> 
> A failing set_type already triggers a kernel message.

I'll remove this.

>> +			return -EBADR;
> 
> That's a pretty odd error. I see it used in 3 drivers (including the
> one this driver replaces), but the canonical error code is -EINVAL.

I'll change it to -EINVAL.

>> +		}
>> +
>> +		irq_set_chip_handler_name_locked(data, chip,
>> +						 handle_fasteoi_irq, NULL);
>> +
>> +		writel_relaxed(nmi_src_type, base + SUN6I_NMI_CTRL);
>> +
>> +		/*
>> +		 * Use the trigger type from the OF node for the NMI's
>> +		 * R_INTC to GIC connection.
>> +		 */
>> +		type = nmi_type;
> 
> This looks wrong. The GIC only supports level-high and edge-rising, so
> half of the possible settings will result in an error. I assume the
> R_INTC has an inverter controlled by nmi_src_type, and only outputs
> something the GIC can grok.

nmi_type isn't the setting from the incoming IRQ. nmi_type is from the
interrupts property in the irqchip OF node itself. So this is a fwspec for
`interrupt-parent = <&gic>;`, i.e. already assumed to be GIC-compatible. I'm not
sure what you mean by "half of the possible settings".

Maybe I should remove the `interrupts` property and hardcode the number and type
connecting to the GIC? If I did that, I'm not quite sure whether it would be
high or rising. The output to the GIC is literally the bit in the pending
register: 1 for pending, 0 for not. Since that is after a latch (regardless of
the input trigger type) it sounds like it should be level-high, because a pulse
would have already been converted to a steady signal. Or does it depend on when
I clear the latch?

>> +	}
>> +
>> +	return irq_chip_set_type_parent(data, type);
>> +}
>> +
>> +static struct irq_chip sun6i_r_intc_edge_chip = {
>> +	.name			= "sun6i-r-intc",
>> +	.irq_mask		= sun6i_r_intc_irq_mask,
>> +	.irq_unmask		= irq_chip_unmask_parent,
>> +	.irq_eoi		= irq_chip_eoi_parent,
>> +	.irq_set_affinity	= irq_chip_set_affinity_parent,
>> +	.irq_set_type		= sun6i_r_intc_irq_set_type,
>> +	.irq_get_irqchip_state	= irq_chip_get_parent_state,
>> +	.irq_set_irqchip_state	= irq_chip_set_parent_state,
>> +	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
>> +	.flags			= IRQCHIP_SET_TYPE_MASKED,
>> +};
>> +
>> +static struct irq_chip sun6i_r_intc_level_chip = {
>> +	.name			= "sun6i-r-intc",
>> +	.irq_mask		= irq_chip_mask_parent,
>> +	.irq_unmask		= sun6i_r_intc_irq_unmask,
>> +	.irq_eoi		= irq_chip_eoi_parent,
>> +	.irq_set_affinity	= irq_chip_set_affinity_parent,
>> +	.irq_set_type		= sun6i_r_intc_irq_set_type,
>> +	.irq_get_irqchip_state	= irq_chip_get_parent_state,
>> +	.irq_set_irqchip_state	= irq_chip_set_parent_state,
>> +	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
>> +	.flags			= IRQCHIP_SET_TYPE_MASKED,
>> +};
>> +
>> +static int sun6i_r_intc_domain_translate(struct irq_domain *domain,
>> +					 struct irq_fwspec *fwspec,
>> +					 unsigned long *hwirq,
>> +					 unsigned int *type)
>> +{
>> +	/* Accept the old two-cell binding for the NMI only. */
>> +	if (fwspec->param_count == 2 && fwspec->param[0] == 0) {
>> +		*hwirq = nmi_hwirq;
>> +		*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
>> +		return 0;
>> +	}
>> +
>> +	/* Otherwise this binding should match the GIC SPI binding. */
>> +	if (fwspec->param_count < 3)
>> +		return -EINVAL;
>> +	if (fwspec->param[0] != GIC_SPI)
>> +		return -EINVAL;
>> +
>> +	*hwirq = fwspec->param[1];
>> +	*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
>> +
>> +	return 0;
>> +}
>> +
>> +static int sun6i_r_intc_domain_alloc(struct irq_domain *domain,
>> +				     unsigned int virq,
>> +				     unsigned int nr_irqs, void *arg)
>> +{
>> +	struct irq_fwspec *fwspec = arg;
>> +	struct irq_fwspec gic_fwspec;
>> +	unsigned long hwirq;
>> +	unsigned int type;
>> +	int i, ret;
>> +
>> +	ret = sun6i_r_intc_domain_translate(domain, fwspec, &hwirq, &type);
>> +	if (ret)
>> +		return ret;
>> +	if (hwirq + nr_irqs > SUN6I_NR_HWIRQS)
>> +		return -EINVAL;
>> +
>> +	/* Construct a GIC-compatible fwspec from this fwspec. */
>> +	gic_fwspec = (struct irq_fwspec) {
>> +		.fwnode      = domain->parent->fwnode,
>> +		.param_count = 3,
>> +		.param       = { GIC_SPI, hwirq, type },
>> +	};
>> +
>> +	for (i = 0; i < nr_irqs; ++i)
>> +		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
>> +					      &sun6i_r_intc_level_chip, NULL);
> 
> Unconditionally level, without looking at the requested type?

__setup_irq calls __irq_set_trigger if any trigger is provided, which calls
chip->irq_set_type unconditionally. So I don't think the chip here matters,
because .irq_set_type will be called before the IRQ is enabled anyway. Again,
maybe I'm missing something.

For non-NMI IRQs, the choice of chip doesn't matter, because this driver handles
nothing but .irq_set_wake for them (should I provide a third chip for this that
doesn't provide its own ack/mask/unmask?).

>> +
>> +	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_fwspec);
>> +}
>> +
>> +static const struct irq_domain_ops sun6i_r_intc_domain_ops = {
>> +	.translate	= sun6i_r_intc_domain_translate,
>> +	.alloc		= sun6i_r_intc_domain_alloc,
>> +	.free		= irq_domain_free_irqs_common,
>> +};
>> +
>> +static void sun6i_r_intc_resume(void)
>> +{
>> +	int i;
>> +
>> +	/* Only the NMI is relevant during normal operation. */
>> +	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_ENABLE(0));
>> +	for (i = 1; i < BITS_TO_U32(SUN6I_NR_IRQS); ++i)
>> +		writel_relaxed(0, base + SUN6I_IRQ_ENABLE(i));
> 
> If only the NMI is relevant, why are the other interrupts enabled?
> Shouldn't this be moved to the following patch (I presume this is
> wake-up related...).

The other IRQs aren't enabled? I'm writing all zeroes to the enable register.

>> +}
>> +
>> +static int __init sun6i_r_intc_init(struct device_node *node,
>> +				    struct device_node *parent)
>> +{
>> +	struct irq_domain *domain, *parent_domain;
>> +	struct of_phandle_args parent_irq;
>> +	int ret;
>> +
>> +	/* Extract the NMI's R_INTC to GIC mapping from the OF node. */
>> +	ret = of_irq_parse_one(node, 0, &parent_irq);
>> +	if (ret)
>> +		return ret;
>> +	if (parent_irq.args_count < 3 || parent_irq.args[0] != GIC_SPI)
>> +		return -EINVAL;
>> +	nmi_hwirq = parent_irq.args[1];
>> +	nmi_type = parent_irq.args[2];
> 
> This looks a lot like the translate callback.

Yes, I could use that here.

>> +
>> +	parent_domain = irq_find_host(parent);
>> +	if (!parent_domain) {
>> +		pr_err("%pOF: Failed to obtain parent domain\n", node);
>> +		return -ENXIO;
>> +	}
>> +
>> +	base = of_io_request_and_map(node, 0, NULL);
>> +	if (IS_ERR(base)) {
>> +		pr_err("%pOF: Failed to map MMIO region\n", node);
>> +		return PTR_ERR(base);
>> +	}
>> +
>> +	sun6i_r_intc_nmi_ack();
>> +	sun6i_r_intc_resume();
>> +
>> +	domain = irq_domain_add_hierarchy(parent_domain, 0,
>> +					  SUN6I_NR_HWIRQS, node,
>> +					  &sun6i_r_intc_domain_ops, NULL);
>> +	if (!domain) {
>> +		pr_err("%pOF: Failed to allocate domain\n", node);
>> +		iounmap(base);
>> +		return -ENOMEM;
>> +	}
>> +
>> +	return 0;
>> +}
>> +IRQCHIP_DECLARE(sun6i_r_intc, "allwinner,sun6i-a31-r-intc", sun6i_r_intc_init);
> 
> Thanks,
> 
> 	M.
> 

Thank you for your (extremely quick, I must say) review!
Samuel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 03/10] irqchip/sun6i-r: Use a stacked irqchip driver
@ 2021-01-03 12:08       ` Samuel Holland
  0 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 12:08 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Ondrej Jirman, devicetree, Jernej Skrabec, Catalin Marinas,
	linux-sunxi, Russell King, Maxime Ripard, linux-kernel,
	Chen-Yu Tsai, Rob Herring, Thomas Gleixner, Will Deacon,
	linux-arm-kernel

On 1/3/21 5:27 AM, Marc Zyngier wrote:
> On Sun, 03 Jan 2021 10:30:54 +0000,
> Samuel Holland <samuel@sholland.org> wrote:
>>
>> The R_INTC in the A31 and newer sun8i/sun50i SoCs is more similar to the
>> original sun4i interrupt controller than the sun7i/sun9i NMI controller.
>> It is used for two distinct purposes:
>>  - To control the trigger, latch, and mask for the NMI input pin
>>  - To provide the interrupt input for the ARISC coprocessor
>>
>> As this interrupt controller is not documented, information about it
>> comes from vendor-provided firmware blobs and from experimentation.
>>
>> Like the original sun4i interrupt controller, it has:
>>  - A VECTOR_REG at 0x00 (configurable via the BASE_ADDR_REG at 0x04)
>>  - A NMI_CTRL_REG, PENDING_REG, and ENABLE_REG as used by both the
>>    sun4i and sunxi-nmi drivers
>>  - A MASK_REG at 0x50
>>  - A RESP_REG at 0x60
>>
>> Differences from the sun4i interrupt controller appear to be:
>>  - It only has one or two registers of each kind (max 32 or 64 IRQs)
>>  - Multiplexing logic is added to support additional inputs
>>  - There is no FIQ-related logic
>>  - There is no interrupt priority logic
>>
>> In order to fulfill its two purposes, this hardware block combines four
>> types of IRQs. First, the NMI pin is routed to the "IRQ 0" input on this
>> chip, with a trigger type controlled by the NMI_CTRL_REG. The "IRQ 0
>> pending" output from this chip, if enabled, is then routed to a SPI IRQ
>> input on the GIC. In other words, bit 0 of IRQ_ENABLE_REG *does* affect
>> the NMI IRQ seen at the GIC.
>>
>> The NMI is followed by a contiguous block of 15 "direct" (my name for
>> them) IRQ inputs that are connected in parallel to both R_INTC and the
>> GIC. Or in other words, these bits of IRQ_ENABLE_REG *do not* affect the
>> IRQs seen at the GIC.
>>
>> Following the direct IRQs are the ARISC's copy of banked IRQs for shared
>> peripherals. These are not relevant to Linux. The remaining IRQs are
>> connected to a multiplexer and provide access to the first (up to) 128
>> SPIs from the ARISC. This range of SPIs overlaps with the direct IRQs.
>>
>> Finally, the global "IRQ pending" output from R_INTC, after being masked
>> by MASK_REG and RESP_REG, is connected to the "external interrupt" input
>> of the ARISC CPU. This path is also irrelevant to Linux.
> 
> An ASCII-art version of this would help a lot, and would look good in
> the driver code...

There is this diagram which I forgot to include in the cover letter:

  https://linux-sunxi.org/images/5/5c/R_INTC.png

I can try to come up with some ASCII art.

>> Because of the 1:1 correspondence between R_INTC and GIC inputs, this is
>> a perfect scenario for using a stacked irqchip driver. We want to hook
>> into enabling/disabling IRQs to add more features to the GIC
>> (specifically to allow masking the NMI and setting its trigger type),
>> but we don't need to actually handle the IRQ in this driver.
>>
>> And since R_INTC is in the always-on power domain, and its output is
>> connected directly in to the power management coprocessor, a stacked
>> irqchip driver provides a simple way to add wakeup support to this set
>> of IRQs. That is the next patch; for now, just the NMI is moved over.
>>
>> To allow access to all multiplexed IRQs, this driver requires a new
>> binding where the interrupt number matches the GIC interrupt number.
>> (This moves the NMI number from 0 to 32 or 96, depending on the SoC.)
>> For simplicity, copy the three-cell GIC binding; this disambiguates
>> interrupt 0 in the old binding (the NMI) from interrupt 0 in the new
>> binding (SPI 0) by the number of cells.
>>
>> This commit mostly reverts commit 173bda53b340 ("irqchip/sunxi-nmi:
>> Support sun6i-a31-r-intc compatible").
>>
>> Signed-off-by: Samuel Holland <samuel@sholland.org>
>> ---
>>  arch/arm/mach-sunxi/Kconfig     |   1 +
>>  arch/arm64/Kconfig.platforms    |   1 +
>>  drivers/irqchip/Makefile        |   1 +
>>  drivers/irqchip/irq-sun6i-r.c   | 267 ++++++++++++++++++++++++++++++++
>>  drivers/irqchip/irq-sunxi-nmi.c |  26 +---
>>  5 files changed, 273 insertions(+), 23 deletions(-)
>>  create mode 100644 drivers/irqchip/irq-sun6i-r.c
>>
> 
> [...]
> 
>> diff --git a/drivers/irqchip/irq-sun6i-r.c b/drivers/irqchip/irq-sun6i-r.c
>> new file mode 100644
>> index 000000000000..7490ade7b254
>> --- /dev/null
>> +++ b/drivers/irqchip/irq-sun6i-r.c
>> @@ -0,0 +1,267 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +//
>> +// R_INTC driver for Allwinner A31 and newer SoCs
>> +//
>> +
>> +#include <linux/irq.h>
>> +#include <linux/irqchip.h>
>> +#include <linux/irqdomain.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_irq.h>
>> +
>> +#include <dt-bindings/interrupt-controller/arm-gic.h>
>> +
>> +/*
>> + * The R_INTC manages between 32 and 64 IRQs, divided into four groups. Example
>> + * bit numbers are for the original variant in the A31:
>> + *
>> + *   Bit      0: The "External NMI" input, connected in series to a GIC SPI.
>> + *   Bits  1-15: "Direct" IRQs for ARISC peripherals, connected in parallel to
>> + *               the GIC and mapped 1:1 to SPIs numerically following the NMI.
>> + *   Bits 16-18: "Banked" IRQs for peripherals that have separate interfaces
>> + *               for the ARM CPUs and ARISC. These do not map to any GIC SPI.
>> + *   Bits 19-31: "Muxed" IRQs, each corresponding to a group of up to 8 SPIs.
>> + *               Later variants added a second PENDING and ENABLE register to
>> + *               make use of all 128 mux inputs (16 IRQ lines).
>> + *
>> + * Since the direct IRQs are inside the muxed IRQ range, they do not increase
>> + * the number of HWIRQs needed.
>> + */
>> +#define SUN6I_NR_IRQS			64
>> +#define SUN6I_NR_DIRECT_IRQS		16
>> +#define SUN6I_NR_MUX_INPUTS		128
>> +#define SUN6I_NR_HWIRQS			SUN6I_NR_MUX_INPUTS
>> +
>> +#define SUN6I_NMI_CTRL			(0x0c)
>> +#define SUN6I_IRQ_PENDING(n)		(0x10 + 4 * (n))
>> +#define SUN6I_IRQ_ENABLE(n)		(0x40 + 4 * (n))
>> +#define SUN6I_MUX_ENABLE(n)		(0xc0 + 4 * (n))
>> +
>> +#define SUN6I_NMI_IRQ_BIT		BIT(0)
>> +
>> +static void __iomem *base;
>> +static irq_hw_number_t nmi_hwirq;
>> +static u32 nmi_type;
>> +
>> +static struct irq_chip sun6i_r_intc_edge_chip;
>> +static struct irq_chip sun6i_r_intc_level_chip;
>> +
>> +static void sun6i_r_intc_nmi_ack(void)
>> +{
>> +	/*
>> +	 * The NMI channel has a latch separate from its trigger type.
>> +	 * This latch must be cleared to clear the signal to the GIC.
>> +	 */
>> +	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_PENDING(0));
>> +}
>> +
>> +static void sun6i_r_intc_irq_mask(struct irq_data *data)
>> +{
>> +	if (data->hwirq == nmi_hwirq)
>> +		sun6i_r_intc_nmi_ack();
> 
> I'm a bit worried by this. I can see it working with level interrupts
> (you can clear the input, and if the interrupt is asserted, it will
> fire again), but I'm worried that it will simply result in lost
> interrupts for edge signalling.

For edge interrupts, don't you want to ack as early as possible, before the
handler clears the source of the interrupt? That way if a second interrupt comes
in while you're handling the first one, you don't ack the second one without
handling it?

> It also begs the question: why would you want to clear the signal to
> the GIC on mask (or unmask)? The expectations are that a pending
> interrupt is preserved across a mask/unmask sequence.

I hadn't thought about anything masking the IRQ outside of the handler; but
you're right, this breaks that case. I'm trying to work within the constraints
of stacking the GIC driver, which assumes handle_fasteoi_irq, so it sounds like
I should switch back to handle_fasteoi_ack_irq and use .irq_ack. Or based on
your previous paragraph, maybe I'm missing some other consideration?

>> +
>> +	irq_chip_mask_parent(data);
>> +}
>> +
>> +static void sun6i_r_intc_irq_unmask(struct irq_data *data)
>> +{
>> +	if (data->hwirq == nmi_hwirq)
>> +		sun6i_r_intc_nmi_ack();
>> +
>> +	irq_chip_unmask_parent(data);
>> +}
>> +
>> +static int sun6i_r_intc_irq_set_type(struct irq_data *data, unsigned int type)
>> +{
>> +	/*
>> +	 * The GIC input labeled "External NMI" connects to bit 0 of the R_INTC
>> +	 * PENDING register, not to the pin directly. So the trigger type of the
>> +	 * GIC input does not depend on the trigger type of the NMI pin itself.
>> +	 *
>> +	 * Only the NMI channel is routed through this interrupt controller on
>> +	 * its way to the GIC. Other IRQs are routed to the GIC and R_INTC in
>> +	 * parallel; they must have a trigger type appropriate for the GIC.
>> +	 */
>> +	if (data->hwirq == nmi_hwirq) {
>> +		struct irq_chip *chip;
>> +		u32 nmi_src_type;
>> +
>> +		switch (type) {
>> +		case IRQ_TYPE_LEVEL_LOW:
>> +			chip = &sun6i_r_intc_level_chip;
>> +			nmi_src_type = 0;
> 
> Please add symbolic names for these types.

I removed them based on your previous comment:

https://lkml.org/lkml/2020/1/20/278
> It is unusual to use an enum for values that get directly programmed into the HW.

Do you want them to be specifically #defines?

>> +			break;
>> +		case IRQ_TYPE_EDGE_FALLING:
>> +			chip = &sun6i_r_intc_edge_chip;
>> +			nmi_src_type = 1;
>> +			break;
>> +		case IRQ_TYPE_LEVEL_HIGH:
>> +			chip = &sun6i_r_intc_level_chip;
>> +			nmi_src_type = 2;
>> +			break;
>> +		case IRQ_TYPE_EDGE_RISING:
>> +			chip = &sun6i_r_intc_edge_chip;
>> +			nmi_src_type = 3;
>> +			break;
>> +		default:
>> +			pr_err("%pOF: invalid trigger type %d for IRQ %d\n",
>> +			       irq_domain_get_of_node(data->domain), type,
>> +			       data->irq);
> 
> A failing set_type already triggers a kernel message.

I'll remove this.

>> +			return -EBADR;
> 
> That's a pretty odd error. I see it used in 3 drivers (including the
> one this driver replaces), but the canonical error code is -EINVAL.

I'll change it to -EINVAL.

>> +		}
>> +
>> +		irq_set_chip_handler_name_locked(data, chip,
>> +						 handle_fasteoi_irq, NULL);
>> +
>> +		writel_relaxed(nmi_src_type, base + SUN6I_NMI_CTRL);
>> +
>> +		/*
>> +		 * Use the trigger type from the OF node for the NMI's
>> +		 * R_INTC to GIC connection.
>> +		 */
>> +		type = nmi_type;
> 
> This looks wrong. The GIC only supports level-high and edge-rising, so
> half of the possible settings will result in an error. I assume the
> R_INTC has an inverter controlled by nmi_src_type, and only outputs
> something the GIC can grok.

nmi_type isn't the setting from the incoming IRQ. nmi_type is from the
interrupts property in the irqchip OF node itself. So this is a fwspec for
`interrupt-parent = <&gic>;`, i.e. already assumed to be GIC-compatible. I'm not
sure what you mean by "half of the possible settings".

Maybe I should remove the `interrupts` property and hardcode the number and type
connecting to the GIC? If I did that, I'm not quite sure whether it would be
high or rising. The output to the GIC is literally the bit in the pending
register: 1 for pending, 0 for not. Since that is after a latch (regardless of
the input trigger type) it sounds like it should be level-high, because a pulse
would have already been converted to a steady signal. Or does it depend on when
I clear the latch?

>> +	}
>> +
>> +	return irq_chip_set_type_parent(data, type);
>> +}
>> +
>> +static struct irq_chip sun6i_r_intc_edge_chip = {
>> +	.name			= "sun6i-r-intc",
>> +	.irq_mask		= sun6i_r_intc_irq_mask,
>> +	.irq_unmask		= irq_chip_unmask_parent,
>> +	.irq_eoi		= irq_chip_eoi_parent,
>> +	.irq_set_affinity	= irq_chip_set_affinity_parent,
>> +	.irq_set_type		= sun6i_r_intc_irq_set_type,
>> +	.irq_get_irqchip_state	= irq_chip_get_parent_state,
>> +	.irq_set_irqchip_state	= irq_chip_set_parent_state,
>> +	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
>> +	.flags			= IRQCHIP_SET_TYPE_MASKED,
>> +};
>> +
>> +static struct irq_chip sun6i_r_intc_level_chip = {
>> +	.name			= "sun6i-r-intc",
>> +	.irq_mask		= irq_chip_mask_parent,
>> +	.irq_unmask		= sun6i_r_intc_irq_unmask,
>> +	.irq_eoi		= irq_chip_eoi_parent,
>> +	.irq_set_affinity	= irq_chip_set_affinity_parent,
>> +	.irq_set_type		= sun6i_r_intc_irq_set_type,
>> +	.irq_get_irqchip_state	= irq_chip_get_parent_state,
>> +	.irq_set_irqchip_state	= irq_chip_set_parent_state,
>> +	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
>> +	.flags			= IRQCHIP_SET_TYPE_MASKED,
>> +};
>> +
>> +static int sun6i_r_intc_domain_translate(struct irq_domain *domain,
>> +					 struct irq_fwspec *fwspec,
>> +					 unsigned long *hwirq,
>> +					 unsigned int *type)
>> +{
>> +	/* Accept the old two-cell binding for the NMI only. */
>> +	if (fwspec->param_count == 2 && fwspec->param[0] == 0) {
>> +		*hwirq = nmi_hwirq;
>> +		*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
>> +		return 0;
>> +	}
>> +
>> +	/* Otherwise this binding should match the GIC SPI binding. */
>> +	if (fwspec->param_count < 3)
>> +		return -EINVAL;
>> +	if (fwspec->param[0] != GIC_SPI)
>> +		return -EINVAL;
>> +
>> +	*hwirq = fwspec->param[1];
>> +	*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
>> +
>> +	return 0;
>> +}
>> +
>> +static int sun6i_r_intc_domain_alloc(struct irq_domain *domain,
>> +				     unsigned int virq,
>> +				     unsigned int nr_irqs, void *arg)
>> +{
>> +	struct irq_fwspec *fwspec = arg;
>> +	struct irq_fwspec gic_fwspec;
>> +	unsigned long hwirq;
>> +	unsigned int type;
>> +	int i, ret;
>> +
>> +	ret = sun6i_r_intc_domain_translate(domain, fwspec, &hwirq, &type);
>> +	if (ret)
>> +		return ret;
>> +	if (hwirq + nr_irqs > SUN6I_NR_HWIRQS)
>> +		return -EINVAL;
>> +
>> +	/* Construct a GIC-compatible fwspec from this fwspec. */
>> +	gic_fwspec = (struct irq_fwspec) {
>> +		.fwnode      = domain->parent->fwnode,
>> +		.param_count = 3,
>> +		.param       = { GIC_SPI, hwirq, type },
>> +	};
>> +
>> +	for (i = 0; i < nr_irqs; ++i)
>> +		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
>> +					      &sun6i_r_intc_level_chip, NULL);
> 
> Unconditionally level, without looking at the requested type?

__setup_irq calls __irq_set_trigger if any trigger is provided, which calls
chip->irq_set_type unconditionally. So I don't think the chip here matters,
because .irq_set_type will be called before the IRQ is enabled anyway. Again,
maybe I'm missing something.

For non-NMI IRQs, the choice of chip doesn't matter, because this driver handles
nothing but .irq_set_wake for them (should I provide a third chip for this that
doesn't provide its own ack/mask/unmask?).

>> +
>> +	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_fwspec);
>> +}
>> +
>> +static const struct irq_domain_ops sun6i_r_intc_domain_ops = {
>> +	.translate	= sun6i_r_intc_domain_translate,
>> +	.alloc		= sun6i_r_intc_domain_alloc,
>> +	.free		= irq_domain_free_irqs_common,
>> +};
>> +
>> +static void sun6i_r_intc_resume(void)
>> +{
>> +	int i;
>> +
>> +	/* Only the NMI is relevant during normal operation. */
>> +	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_ENABLE(0));
>> +	for (i = 1; i < BITS_TO_U32(SUN6I_NR_IRQS); ++i)
>> +		writel_relaxed(0, base + SUN6I_IRQ_ENABLE(i));
> 
> If only the NMI is relevant, why are the other interrupts enabled?
> Shouldn't this be moved to the following patch (I presume this is
> wake-up related...).

The other IRQs aren't enabled? I'm writing all zeroes to the enable register.

>> +}
>> +
>> +static int __init sun6i_r_intc_init(struct device_node *node,
>> +				    struct device_node *parent)
>> +{
>> +	struct irq_domain *domain, *parent_domain;
>> +	struct of_phandle_args parent_irq;
>> +	int ret;
>> +
>> +	/* Extract the NMI's R_INTC to GIC mapping from the OF node. */
>> +	ret = of_irq_parse_one(node, 0, &parent_irq);
>> +	if (ret)
>> +		return ret;
>> +	if (parent_irq.args_count < 3 || parent_irq.args[0] != GIC_SPI)
>> +		return -EINVAL;
>> +	nmi_hwirq = parent_irq.args[1];
>> +	nmi_type = parent_irq.args[2];
> 
> This looks a lot like the translate callback.

Yes, I could use that here.

>> +
>> +	parent_domain = irq_find_host(parent);
>> +	if (!parent_domain) {
>> +		pr_err("%pOF: Failed to obtain parent domain\n", node);
>> +		return -ENXIO;
>> +	}
>> +
>> +	base = of_io_request_and_map(node, 0, NULL);
>> +	if (IS_ERR(base)) {
>> +		pr_err("%pOF: Failed to map MMIO region\n", node);
>> +		return PTR_ERR(base);
>> +	}
>> +
>> +	sun6i_r_intc_nmi_ack();
>> +	sun6i_r_intc_resume();
>> +
>> +	domain = irq_domain_add_hierarchy(parent_domain, 0,
>> +					  SUN6I_NR_HWIRQS, node,
>> +					  &sun6i_r_intc_domain_ops, NULL);
>> +	if (!domain) {
>> +		pr_err("%pOF: Failed to allocate domain\n", node);
>> +		iounmap(base);
>> +		return -ENOMEM;
>> +	}
>> +
>> +	return 0;
>> +}
>> +IRQCHIP_DECLARE(sun6i_r_intc, "allwinner,sun6i-a31-r-intc", sun6i_r_intc_init);
> 
> Thanks,
> 
> 	M.
> 

Thank you for your (extremely quick, I must say) review!
Samuel

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 00/10] sunxi: Support IRQ wakeup from deep sleep
  2021-01-03 10:30 ` Samuel Holland
@ 2021-01-03 12:16   ` Marc Zyngier
  -1 siblings, 0 replies; 44+ messages in thread
From: Marc Zyngier @ 2021-01-03 12:16 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Thomas Gleixner, Rob Herring, Maxime Ripard, Chen-Yu Tsai,
	Jernej Skrabec, Russell King, Catalin Marinas, Will Deacon,
	Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel

[dropped linux-sunxi@googlegroups.com, which seems to be a closed ML]

On Sun, 03 Jan 2021 10:30:51 +0000,
Samuel Holland <samuel@sholland.org> wrote:
> 
> Allwinner sun6i/sun8i/sun50i SoCs (A31 and newer) have two interrupt
> controllers: GIC and R_INTC. GIC does not support wakeup. R_INTC handles
> the external NMI pin, and provides 32+ IRQs to the ARISC. The first 16
> of these correspond 1:1 to a block of GIC IRQs starting with the NMI.
> The last 13-16 multiplex the first (up to) 128 GIC SPIs.
> 
> This series replaces the existing chained irqchip driver that could only
> control the NMI, with a stacked irqchip driver that also provides wakeup
> capability for those multiplexed SPI IRQs. The idea is to preconfigure
> the ARISC's IRQ controller, and then the ARISC firmware knows to wake up
> as soon as it receives an IRQ. It can also decide how deep it can
> suspend based on the selected wakeup IRQs.

Out of curiosity, how do you plan to communicate dynamic configuration
of IRQs to the ARISC? We recently went through this with some TI
stuff, and the result a bit awkward (the arm64 side configures
interrupts that are not visible to the kernel, but only to the
co-processors).

I wondered whether you had other ideas...

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 00/10] sunxi: Support IRQ wakeup from deep sleep
@ 2021-01-03 12:16   ` Marc Zyngier
  0 siblings, 0 replies; 44+ messages in thread
From: Marc Zyngier @ 2021-01-03 12:16 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, devicetree, Jernej Skrabec, Catalin Marinas,
	Russell King, Maxime Ripard, linux-kernel, Chen-Yu Tsai,
	Rob Herring, Thomas Gleixner, Will Deacon, linux-arm-kernel

[dropped linux-sunxi@googlegroups.com, which seems to be a closed ML]

On Sun, 03 Jan 2021 10:30:51 +0000,
Samuel Holland <samuel@sholland.org> wrote:
> 
> Allwinner sun6i/sun8i/sun50i SoCs (A31 and newer) have two interrupt
> controllers: GIC and R_INTC. GIC does not support wakeup. R_INTC handles
> the external NMI pin, and provides 32+ IRQs to the ARISC. The first 16
> of these correspond 1:1 to a block of GIC IRQs starting with the NMI.
> The last 13-16 multiplex the first (up to) 128 GIC SPIs.
> 
> This series replaces the existing chained irqchip driver that could only
> control the NMI, with a stacked irqchip driver that also provides wakeup
> capability for those multiplexed SPI IRQs. The idea is to preconfigure
> the ARISC's IRQ controller, and then the ARISC firmware knows to wake up
> as soon as it receives an IRQ. It can also decide how deep it can
> suspend based on the selected wakeup IRQs.

Out of curiosity, how do you plan to communicate dynamic configuration
of IRQs to the ARISC? We recently went through this with some TI
stuff, and the result a bit awkward (the arm64 side configures
interrupts that are not visible to the kernel, but only to the
co-processors).

I wondered whether you had other ideas...

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 00/10] sunxi: Support IRQ wakeup from deep sleep
  2021-01-03 12:16   ` Marc Zyngier
@ 2021-01-03 12:43     ` Samuel Holland
  -1 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 12:43 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Thomas Gleixner, Rob Herring, Maxime Ripard, Chen-Yu Tsai,
	Jernej Skrabec, Russell King, Catalin Marinas, Will Deacon,
	Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel

On 1/3/21 6:16 AM, Marc Zyngier wrote:
> [dropped linux-sunxi@googlegroups.com, which seems to be a closed ML]
> 
> On Sun, 03 Jan 2021 10:30:51 +0000,
> Samuel Holland <samuel@sholland.org> wrote:
>>
>> Allwinner sun6i/sun8i/sun50i SoCs (A31 and newer) have two interrupt
>> controllers: GIC and R_INTC. GIC does not support wakeup. R_INTC handles
>> the external NMI pin, and provides 32+ IRQs to the ARISC. The first 16
>> of these correspond 1:1 to a block of GIC IRQs starting with the NMI.
>> The last 13-16 multiplex the first (up to) 128 GIC SPIs.
>>
>> This series replaces the existing chained irqchip driver that could only
>> control the NMI, with a stacked irqchip driver that also provides wakeup
>> capability for those multiplexed SPI IRQs. The idea is to preconfigure
>> the ARISC's IRQ controller, and then the ARISC firmware knows to wake up
>> as soon as it receives an IRQ. It can also decide how deep it can
>> suspend based on the selected wakeup IRQs.
> 
> Out of curiosity, how do you plan to communicate dynamic configuration
> of IRQs to the ARISC? We recently went through this with some TI
> stuff, and the result a bit awkward (the arm64 side configures
> interrupts that are not visible to the kernel, but only to the
> co-processors).

Assuming by "dynamic" you mean while Linux is running, I don't plan to
communicate anything. As far as I'm concerned, the driver is feature-complete
after this patch series. The ARISC firmware does not use the interrupt
controller (or any other shared peripherals) while Linux is running. It sits in
a tight loop polling its side of the mailbox, waiting for a
hotplug/suspend/poweroff/reboot command.

> I wondered whether you had other ideas...

Sorry, I guess not. We tried to avoid using the ARISC for long enough that
anything that can have a native Linux driver has one. So the ARISC firmware has
nothing to do while Linux is running. (This is in comparison to the vendor BSP,
where some peripherals are only accessed through their firmware.)

Samuel

> Thanks,
> 
> 	M.
> 


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 00/10] sunxi: Support IRQ wakeup from deep sleep
@ 2021-01-03 12:43     ` Samuel Holland
  0 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-03 12:43 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Ondrej Jirman, devicetree, Jernej Skrabec, Catalin Marinas,
	Russell King, Maxime Ripard, linux-kernel, Chen-Yu Tsai,
	Rob Herring, Thomas Gleixner, Will Deacon, linux-arm-kernel

On 1/3/21 6:16 AM, Marc Zyngier wrote:
> [dropped linux-sunxi@googlegroups.com, which seems to be a closed ML]
> 
> On Sun, 03 Jan 2021 10:30:51 +0000,
> Samuel Holland <samuel@sholland.org> wrote:
>>
>> Allwinner sun6i/sun8i/sun50i SoCs (A31 and newer) have two interrupt
>> controllers: GIC and R_INTC. GIC does not support wakeup. R_INTC handles
>> the external NMI pin, and provides 32+ IRQs to the ARISC. The first 16
>> of these correspond 1:1 to a block of GIC IRQs starting with the NMI.
>> The last 13-16 multiplex the first (up to) 128 GIC SPIs.
>>
>> This series replaces the existing chained irqchip driver that could only
>> control the NMI, with a stacked irqchip driver that also provides wakeup
>> capability for those multiplexed SPI IRQs. The idea is to preconfigure
>> the ARISC's IRQ controller, and then the ARISC firmware knows to wake up
>> as soon as it receives an IRQ. It can also decide how deep it can
>> suspend based on the selected wakeup IRQs.
> 
> Out of curiosity, how do you plan to communicate dynamic configuration
> of IRQs to the ARISC? We recently went through this with some TI
> stuff, and the result a bit awkward (the arm64 side configures
> interrupts that are not visible to the kernel, but only to the
> co-processors).

Assuming by "dynamic" you mean while Linux is running, I don't plan to
communicate anything. As far as I'm concerned, the driver is feature-complete
after this patch series. The ARISC firmware does not use the interrupt
controller (or any other shared peripherals) while Linux is running. It sits in
a tight loop polling its side of the mailbox, waiting for a
hotplug/suspend/poweroff/reboot command.

> I wondered whether you had other ideas...

Sorry, I guess not. We tried to avoid using the ARISC for long enough that
anything that can have a native Linux driver has one. So the ARISC firmware has
nothing to do while Linux is running. (This is in comparison to the vendor BSP,
where some peripherals are only accessed through their firmware.)

Samuel

> Thanks,
> 
> 	M.
> 


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 03/10] irqchip/sun6i-r: Use a stacked irqchip driver
  2021-01-03 12:08       ` Samuel Holland
@ 2021-01-03 13:10         ` Marc Zyngier
  -1 siblings, 0 replies; 44+ messages in thread
From: Marc Zyngier @ 2021-01-03 13:10 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Thomas Gleixner, Rob Herring, Maxime Ripard, Chen-Yu Tsai,
	Jernej Skrabec, Russell King, Catalin Marinas, Will Deacon,
	Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel

On Sun, 03 Jan 2021 12:08:43 +0000,
Samuel Holland <samuel@sholland.org> wrote:
> 
> On 1/3/21 5:27 AM, Marc Zyngier wrote:
> > On Sun, 03 Jan 2021 10:30:54 +0000,
> > Samuel Holland <samuel@sholland.org> wrote:
> >>
> >> The R_INTC in the A31 and newer sun8i/sun50i SoCs is more similar to the
> >> original sun4i interrupt controller than the sun7i/sun9i NMI controller.
> >> It is used for two distinct purposes:
> >>  - To control the trigger, latch, and mask for the NMI input pin
> >>  - To provide the interrupt input for the ARISC coprocessor
> >>
> >> As this interrupt controller is not documented, information about it
> >> comes from vendor-provided firmware blobs and from experimentation.
> >>
> >> Like the original sun4i interrupt controller, it has:
> >>  - A VECTOR_REG at 0x00 (configurable via the BASE_ADDR_REG at 0x04)
> >>  - A NMI_CTRL_REG, PENDING_REG, and ENABLE_REG as used by both the
> >>    sun4i and sunxi-nmi drivers
> >>  - A MASK_REG at 0x50
> >>  - A RESP_REG at 0x60
> >>
> >> Differences from the sun4i interrupt controller appear to be:
> >>  - It only has one or two registers of each kind (max 32 or 64 IRQs)
> >>  - Multiplexing logic is added to support additional inputs
> >>  - There is no FIQ-related logic
> >>  - There is no interrupt priority logic
> >>
> >> In order to fulfill its two purposes, this hardware block combines four
> >> types of IRQs. First, the NMI pin is routed to the "IRQ 0" input on this
> >> chip, with a trigger type controlled by the NMI_CTRL_REG. The "IRQ 0
> >> pending" output from this chip, if enabled, is then routed to a SPI IRQ
> >> input on the GIC. In other words, bit 0 of IRQ_ENABLE_REG *does* affect
> >> the NMI IRQ seen at the GIC.
> >>
> >> The NMI is followed by a contiguous block of 15 "direct" (my name for
> >> them) IRQ inputs that are connected in parallel to both R_INTC and the
> >> GIC. Or in other words, these bits of IRQ_ENABLE_REG *do not* affect the
> >> IRQs seen at the GIC.
> >>
> >> Following the direct IRQs are the ARISC's copy of banked IRQs for shared
> >> peripherals. These are not relevant to Linux. The remaining IRQs are
> >> connected to a multiplexer and provide access to the first (up to) 128
> >> SPIs from the ARISC. This range of SPIs overlaps with the direct IRQs.
> >>
> >> Finally, the global "IRQ pending" output from R_INTC, after being masked
> >> by MASK_REG and RESP_REG, is connected to the "external interrupt" input
> >> of the ARISC CPU. This path is also irrelevant to Linux.
> > 
> > An ASCII-art version of this would help a lot, and would look good in
> > the driver code...
> 
> There is this diagram which I forgot to include in the cover letter:
> 
>   https://linux-sunxi.org/images/5/5c/R_INTC.png
> 
> I can try to come up with some ASCII art.
> 
> >> Because of the 1:1 correspondence between R_INTC and GIC inputs, this is
> >> a perfect scenario for using a stacked irqchip driver. We want to hook
> >> into enabling/disabling IRQs to add more features to the GIC
> >> (specifically to allow masking the NMI and setting its trigger type),
> >> but we don't need to actually handle the IRQ in this driver.
> >>
> >> And since R_INTC is in the always-on power domain, and its output is
> >> connected directly in to the power management coprocessor, a stacked
> >> irqchip driver provides a simple way to add wakeup support to this set
> >> of IRQs. That is the next patch; for now, just the NMI is moved over.
> >>
> >> To allow access to all multiplexed IRQs, this driver requires a new
> >> binding where the interrupt number matches the GIC interrupt number.
> >> (This moves the NMI number from 0 to 32 or 96, depending on the SoC.)
> >> For simplicity, copy the three-cell GIC binding; this disambiguates
> >> interrupt 0 in the old binding (the NMI) from interrupt 0 in the new
> >> binding (SPI 0) by the number of cells.
> >>
> >> This commit mostly reverts commit 173bda53b340 ("irqchip/sunxi-nmi:
> >> Support sun6i-a31-r-intc compatible").
> >>
> >> Signed-off-by: Samuel Holland <samuel@sholland.org>
> >> ---
> >>  arch/arm/mach-sunxi/Kconfig     |   1 +
> >>  arch/arm64/Kconfig.platforms    |   1 +
> >>  drivers/irqchip/Makefile        |   1 +
> >>  drivers/irqchip/irq-sun6i-r.c   | 267 ++++++++++++++++++++++++++++++++
> >>  drivers/irqchip/irq-sunxi-nmi.c |  26 +---
> >>  5 files changed, 273 insertions(+), 23 deletions(-)
> >>  create mode 100644 drivers/irqchip/irq-sun6i-r.c
> >>
> > 
> > [...]
> > 
> >> diff --git a/drivers/irqchip/irq-sun6i-r.c b/drivers/irqchip/irq-sun6i-r.c
> >> new file mode 100644
> >> index 000000000000..7490ade7b254
> >> --- /dev/null
> >> +++ b/drivers/irqchip/irq-sun6i-r.c
> >> @@ -0,0 +1,267 @@
> >> +// SPDX-License-Identifier: GPL-2.0-only
> >> +//
> >> +// R_INTC driver for Allwinner A31 and newer SoCs
> >> +//
> >> +
> >> +#include <linux/irq.h>
> >> +#include <linux/irqchip.h>
> >> +#include <linux/irqdomain.h>
> >> +#include <linux/of.h>
> >> +#include <linux/of_address.h>
> >> +#include <linux/of_irq.h>
> >> +
> >> +#include <dt-bindings/interrupt-controller/arm-gic.h>
> >> +
> >> +/*
> >> + * The R_INTC manages between 32 and 64 IRQs, divided into four groups. Example
> >> + * bit numbers are for the original variant in the A31:
> >> + *
> >> + *   Bit      0: The "External NMI" input, connected in series to a GIC SPI.
> >> + *   Bits  1-15: "Direct" IRQs for ARISC peripherals, connected in parallel to
> >> + *               the GIC and mapped 1:1 to SPIs numerically following the NMI.
> >> + *   Bits 16-18: "Banked" IRQs for peripherals that have separate interfaces
> >> + *               for the ARM CPUs and ARISC. These do not map to any GIC SPI.
> >> + *   Bits 19-31: "Muxed" IRQs, each corresponding to a group of up to 8 SPIs.
> >> + *               Later variants added a second PENDING and ENABLE register to
> >> + *               make use of all 128 mux inputs (16 IRQ lines).
> >> + *
> >> + * Since the direct IRQs are inside the muxed IRQ range, they do not increase
> >> + * the number of HWIRQs needed.
> >> + */
> >> +#define SUN6I_NR_IRQS			64
> >> +#define SUN6I_NR_DIRECT_IRQS		16
> >> +#define SUN6I_NR_MUX_INPUTS		128
> >> +#define SUN6I_NR_HWIRQS			SUN6I_NR_MUX_INPUTS
> >> +
> >> +#define SUN6I_NMI_CTRL			(0x0c)
> >> +#define SUN6I_IRQ_PENDING(n)		(0x10 + 4 * (n))
> >> +#define SUN6I_IRQ_ENABLE(n)		(0x40 + 4 * (n))
> >> +#define SUN6I_MUX_ENABLE(n)		(0xc0 + 4 * (n))
> >> +
> >> +#define SUN6I_NMI_IRQ_BIT		BIT(0)
> >> +
> >> +static void __iomem *base;
> >> +static irq_hw_number_t nmi_hwirq;
> >> +static u32 nmi_type;
> >> +
> >> +static struct irq_chip sun6i_r_intc_edge_chip;
> >> +static struct irq_chip sun6i_r_intc_level_chip;
> >> +
> >> +static void sun6i_r_intc_nmi_ack(void)
> >> +{
> >> +	/*
> >> +	 * The NMI channel has a latch separate from its trigger type.
> >> +	 * This latch must be cleared to clear the signal to the GIC.
> >> +	 */
> >> +	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_PENDING(0));
> >> +}
> >> +
> >> +static void sun6i_r_intc_irq_mask(struct irq_data *data)
> >> +{
> >> +	if (data->hwirq == nmi_hwirq)
> >> +		sun6i_r_intc_nmi_ack();
> > 
> > I'm a bit worried by this. I can see it working with level interrupts
> > (you can clear the input, and if the interrupt is asserted, it will
> > fire again), but I'm worried that it will simply result in lost
> > interrupts for edge signalling.
> 
> For edge interrupts, don't you want to ack as early as possible,
> before the handler clears the source of the interrupt? That way if a
> second interrupt comes in while you're handling the first one, you
> don't ack the second one without handling it?

It completely depends on what this block does. If, as I expect, it
latches the interrupt, then it needs clearing after the GIC has acked
the incoming interrupt.

> > It also begs the question: why would you want to clear the signal to
> > the GIC on mask (or unmask)? The expectations are that a pending
> > interrupt is preserved across a mask/unmask sequence.
> 
> I hadn't thought about anything masking the IRQ outside of the
> handler; but you're right, this breaks that case. I'm trying to work
> within the constraints of stacking the GIC driver, which assumes
> handle_fasteoi_irq, so it sounds like I should switch back to
> handle_fasteoi_ack_irq and use .irq_ack. Or based on your previous
> paragraph, maybe I'm missing some other consideration?

handle_fasteoi_ack_irq() sounds like a good match for edge
interrupts. Do you actually need to do anything for level signals? If
you do, piggybacking on .irq_eoi would do the trick.

> 
> >> +
> >> +	irq_chip_mask_parent(data);
> >> +}
> >> +
> >> +static void sun6i_r_intc_irq_unmask(struct irq_data *data)
> >> +{
> >> +	if (data->hwirq == nmi_hwirq)
> >> +		sun6i_r_intc_nmi_ack();
> >> +
> >> +	irq_chip_unmask_parent(data);
> >> +}
> >> +
> >> +static int sun6i_r_intc_irq_set_type(struct irq_data *data, unsigned int type)
> >> +{
> >> +	/*
> >> +	 * The GIC input labeled "External NMI" connects to bit 0 of the R_INTC
> >> +	 * PENDING register, not to the pin directly. So the trigger type of the
> >> +	 * GIC input does not depend on the trigger type of the NMI pin itself.
> >> +	 *
> >> +	 * Only the NMI channel is routed through this interrupt controller on
> >> +	 * its way to the GIC. Other IRQs are routed to the GIC and R_INTC in
> >> +	 * parallel; they must have a trigger type appropriate for the GIC.
> >> +	 */
> >> +	if (data->hwirq == nmi_hwirq) {
> >> +		struct irq_chip *chip;
> >> +		u32 nmi_src_type;
> >> +
> >> +		switch (type) {
> >> +		case IRQ_TYPE_LEVEL_LOW:
> >> +			chip = &sun6i_r_intc_level_chip;
> >> +			nmi_src_type = 0;
> > 
> > Please add symbolic names for these types.
> 
> I removed them based on your previous comment:
> 
> https://lkml.org/lkml/2020/1/20/278
> > It is unusual to use an enum for values that get directly programmed into the HW.
> 
> Do you want them to be specifically #defines?

Yes please.

> 
> >> +			break;
> >> +		case IRQ_TYPE_EDGE_FALLING:
> >> +			chip = &sun6i_r_intc_edge_chip;
> >> +			nmi_src_type = 1;
> >> +			break;
> >> +		case IRQ_TYPE_LEVEL_HIGH:
> >> +			chip = &sun6i_r_intc_level_chip;
> >> +			nmi_src_type = 2;
> >> +			break;
> >> +		case IRQ_TYPE_EDGE_RISING:
> >> +			chip = &sun6i_r_intc_edge_chip;
> >> +			nmi_src_type = 3;
> >> +			break;
> >> +		default:
> >> +			pr_err("%pOF: invalid trigger type %d for IRQ %d\n",
> >> +			       irq_domain_get_of_node(data->domain), type,
> >> +			       data->irq);
> > 
> > A failing set_type already triggers a kernel message.
> 
> I'll remove this.
> 
> >> +			return -EBADR;
> > 
> > That's a pretty odd error. I see it used in 3 drivers (including the
> > one this driver replaces), but the canonical error code is -EINVAL.
> 
> I'll change it to -EINVAL.
> 
> >> +		}
> >> +
> >> +		irq_set_chip_handler_name_locked(data, chip,
> >> +						 handle_fasteoi_irq, NULL);
> >> +
> >> +		writel_relaxed(nmi_src_type, base + SUN6I_NMI_CTRL);
> >> +
> >> +		/*
> >> +		 * Use the trigger type from the OF node for the NMI's
> >> +		 * R_INTC to GIC connection.
> >> +		 */
> >> +		type = nmi_type;
> > 
> > This looks wrong. The GIC only supports level-high and edge-rising, so
> > half of the possible settings will result in an error. I assume the
> > R_INTC has an inverter controlled by nmi_src_type, and only outputs
> > something the GIC can grok.
> 
> nmi_type isn't the setting from the incoming IRQ. nmi_type is from
> the interrupts property in the irqchip OF node itself. So this is a
> fwspec for `interrupt-parent = <&gic>;`, i.e. already assumed to be
> GIC-compatible. I'm not sure what you mean by "half of the possible
> settings".

Ah, I see. I misread where nmi_type was coming from. Please ignore me.

> 
> Maybe I should remove the `interrupts` property and hardcode the
> number and type connecting to the GIC? If I did that, I'm not quite
> sure whether it would be high or rising.

I guess that the output of this block is a level signal, so you should
probably enforce that.

> The output to the GIC is literally the bit in the pending register:
> 1 for pending, 0 for not. Since that is after a latch (regardless of
> the input trigger type) it sounds like it should be level-high,
> because a pulse would have already been converted to a steady
> signal. Or does it depend on when I clear the latch?

Level and edge will have different latch clearing requirements, as
outlined above. For level, it needs to be cleared after handling the
interrupt, at the point where you would deactivate it in the GIC
(.irq_eoi). For edge, that's an Ack.

[...]

> >> +static int sun6i_r_intc_domain_alloc(struct irq_domain *domain,
> >> +				     unsigned int virq,
> >> +				     unsigned int nr_irqs, void *arg)
> >> +{
> >> +	struct irq_fwspec *fwspec = arg;
> >> +	struct irq_fwspec gic_fwspec;
> >> +	unsigned long hwirq;
> >> +	unsigned int type;
> >> +	int i, ret;
> >> +
> >> +	ret = sun6i_r_intc_domain_translate(domain, fwspec, &hwirq, &type);
> >> +	if (ret)
> >> +		return ret;
> >> +	if (hwirq + nr_irqs > SUN6I_NR_HWIRQS)
> >> +		return -EINVAL;
> >> +
> >> +	/* Construct a GIC-compatible fwspec from this fwspec. */
> >> +	gic_fwspec = (struct irq_fwspec) {
> >> +		.fwnode      = domain->parent->fwnode,
> >> +		.param_count = 3,
> >> +		.param       = { GIC_SPI, hwirq, type },
> >> +	};
> >> +
> >> +	for (i = 0; i < nr_irqs; ++i)
> >> +		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
> >> +					      &sun6i_r_intc_level_chip, NULL);
> > 
> > Unconditionally level, without looking at the requested type?
> 
> __setup_irq calls __irq_set_trigger if any trigger is provided, which calls
> chip->irq_set_type unconditionally. So I don't think the chip here matters,
> because .irq_set_type will be called before the IRQ is enabled anyway. Again,
> maybe I'm missing something.

It doesn't really matter, but it is a bit odd to have the information
at hand, and ignore it. This at least deserves a comment.

> For non-NMI IRQs, the choice of chip doesn't matter, because this
> driver handles nothing but .irq_set_wake for them (should I provide
> a third chip for this that doesn't provide its own
> ack/mask/unmask?).

I think you could handle the NMI with its own single irqchip (for both
level and edge, only checking for the configuration in ack/eoi), and
have a non-NMI chip for the rest.

> 
> >> +
> >> +	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_fwspec);
> >> +}
> >> +
> >> +static const struct irq_domain_ops sun6i_r_intc_domain_ops = {
> >> +	.translate	= sun6i_r_intc_domain_translate,
> >> +	.alloc		= sun6i_r_intc_domain_alloc,
> >> +	.free		= irq_domain_free_irqs_common,
> >> +};
> >> +
> >> +static void sun6i_r_intc_resume(void)
> >> +{
> >> +	int i;
> >> +
> >> +	/* Only the NMI is relevant during normal operation. */
> >> +	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_ENABLE(0));
> >> +	for (i = 1; i < BITS_TO_U32(SUN6I_NR_IRQS); ++i)
> >> +		writel_relaxed(0, base + SUN6I_IRQ_ENABLE(i));
> > 
> > If only the NMI is relevant, why are the other interrupts enabled?
> > Shouldn't this be moved to the following patch (I presume this is
> > wake-up related...).
> 
> The other IRQs aren't enabled? I'm writing all zeroes to the enable register.

Duh. -ECANTREAD.

> >> +}
> >> +
> >> +static int __init sun6i_r_intc_init(struct device_node *node,
> >> +				    struct device_node *parent)
> >> +{
> >> +	struct irq_domain *domain, *parent_domain;
> >> +	struct of_phandle_args parent_irq;
> >> +	int ret;
> >> +
> >> +	/* Extract the NMI's R_INTC to GIC mapping from the OF node. */
> >> +	ret = of_irq_parse_one(node, 0, &parent_irq);
> >> +	if (ret)
> >> +		return ret;
> >> +	if (parent_irq.args_count < 3 || parent_irq.args[0] != GIC_SPI)
> >> +		return -EINVAL;
> >> +	nmi_hwirq = parent_irq.args[1];
> >> +	nmi_type = parent_irq.args[2];
> > 
> > This looks a lot like the translate callback.
> 
> Yes, I could use that here.
> 
> >> +
> >> +	parent_domain = irq_find_host(parent);
> >> +	if (!parent_domain) {
> >> +		pr_err("%pOF: Failed to obtain parent domain\n", node);
> >> +		return -ENXIO;
> >> +	}
> >> +
> >> +	base = of_io_request_and_map(node, 0, NULL);
> >> +	if (IS_ERR(base)) {
> >> +		pr_err("%pOF: Failed to map MMIO region\n", node);
> >> +		return PTR_ERR(base);
> >> +	}
> >> +
> >> +	sun6i_r_intc_nmi_ack();
> >> +	sun6i_r_intc_resume();
> >> +
> >> +	domain = irq_domain_add_hierarchy(parent_domain, 0,
> >> +					  SUN6I_NR_HWIRQS, node,
> >> +					  &sun6i_r_intc_domain_ops, NULL);
> >> +	if (!domain) {
> >> +		pr_err("%pOF: Failed to allocate domain\n", node);
> >> +		iounmap(base);
> >> +		return -ENOMEM;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +IRQCHIP_DECLARE(sun6i_r_intc, "allwinner,sun6i-a31-r-intc", sun6i_r_intc_init);
> > 
> > Thanks,
> > 
> > 	M.
> > 
> 
> Thank you for your (extremely quick, I must say) review!

Locked up home until Wednesday. I try to keep myself busy...

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 03/10] irqchip/sun6i-r: Use a stacked irqchip driver
@ 2021-01-03 13:10         ` Marc Zyngier
  0 siblings, 0 replies; 44+ messages in thread
From: Marc Zyngier @ 2021-01-03 13:10 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, devicetree, Jernej Skrabec, Catalin Marinas,
	Russell King, Maxime Ripard, linux-kernel, Chen-Yu Tsai,
	Rob Herring, Thomas Gleixner, Will Deacon, linux-arm-kernel

On Sun, 03 Jan 2021 12:08:43 +0000,
Samuel Holland <samuel@sholland.org> wrote:
> 
> On 1/3/21 5:27 AM, Marc Zyngier wrote:
> > On Sun, 03 Jan 2021 10:30:54 +0000,
> > Samuel Holland <samuel@sholland.org> wrote:
> >>
> >> The R_INTC in the A31 and newer sun8i/sun50i SoCs is more similar to the
> >> original sun4i interrupt controller than the sun7i/sun9i NMI controller.
> >> It is used for two distinct purposes:
> >>  - To control the trigger, latch, and mask for the NMI input pin
> >>  - To provide the interrupt input for the ARISC coprocessor
> >>
> >> As this interrupt controller is not documented, information about it
> >> comes from vendor-provided firmware blobs and from experimentation.
> >>
> >> Like the original sun4i interrupt controller, it has:
> >>  - A VECTOR_REG at 0x00 (configurable via the BASE_ADDR_REG at 0x04)
> >>  - A NMI_CTRL_REG, PENDING_REG, and ENABLE_REG as used by both the
> >>    sun4i and sunxi-nmi drivers
> >>  - A MASK_REG at 0x50
> >>  - A RESP_REG at 0x60
> >>
> >> Differences from the sun4i interrupt controller appear to be:
> >>  - It only has one or two registers of each kind (max 32 or 64 IRQs)
> >>  - Multiplexing logic is added to support additional inputs
> >>  - There is no FIQ-related logic
> >>  - There is no interrupt priority logic
> >>
> >> In order to fulfill its two purposes, this hardware block combines four
> >> types of IRQs. First, the NMI pin is routed to the "IRQ 0" input on this
> >> chip, with a trigger type controlled by the NMI_CTRL_REG. The "IRQ 0
> >> pending" output from this chip, if enabled, is then routed to a SPI IRQ
> >> input on the GIC. In other words, bit 0 of IRQ_ENABLE_REG *does* affect
> >> the NMI IRQ seen at the GIC.
> >>
> >> The NMI is followed by a contiguous block of 15 "direct" (my name for
> >> them) IRQ inputs that are connected in parallel to both R_INTC and the
> >> GIC. Or in other words, these bits of IRQ_ENABLE_REG *do not* affect the
> >> IRQs seen at the GIC.
> >>
> >> Following the direct IRQs are the ARISC's copy of banked IRQs for shared
> >> peripherals. These are not relevant to Linux. The remaining IRQs are
> >> connected to a multiplexer and provide access to the first (up to) 128
> >> SPIs from the ARISC. This range of SPIs overlaps with the direct IRQs.
> >>
> >> Finally, the global "IRQ pending" output from R_INTC, after being masked
> >> by MASK_REG and RESP_REG, is connected to the "external interrupt" input
> >> of the ARISC CPU. This path is also irrelevant to Linux.
> > 
> > An ASCII-art version of this would help a lot, and would look good in
> > the driver code...
> 
> There is this diagram which I forgot to include in the cover letter:
> 
>   https://linux-sunxi.org/images/5/5c/R_INTC.png
> 
> I can try to come up with some ASCII art.
> 
> >> Because of the 1:1 correspondence between R_INTC and GIC inputs, this is
> >> a perfect scenario for using a stacked irqchip driver. We want to hook
> >> into enabling/disabling IRQs to add more features to the GIC
> >> (specifically to allow masking the NMI and setting its trigger type),
> >> but we don't need to actually handle the IRQ in this driver.
> >>
> >> And since R_INTC is in the always-on power domain, and its output is
> >> connected directly in to the power management coprocessor, a stacked
> >> irqchip driver provides a simple way to add wakeup support to this set
> >> of IRQs. That is the next patch; for now, just the NMI is moved over.
> >>
> >> To allow access to all multiplexed IRQs, this driver requires a new
> >> binding where the interrupt number matches the GIC interrupt number.
> >> (This moves the NMI number from 0 to 32 or 96, depending on the SoC.)
> >> For simplicity, copy the three-cell GIC binding; this disambiguates
> >> interrupt 0 in the old binding (the NMI) from interrupt 0 in the new
> >> binding (SPI 0) by the number of cells.
> >>
> >> This commit mostly reverts commit 173bda53b340 ("irqchip/sunxi-nmi:
> >> Support sun6i-a31-r-intc compatible").
> >>
> >> Signed-off-by: Samuel Holland <samuel@sholland.org>
> >> ---
> >>  arch/arm/mach-sunxi/Kconfig     |   1 +
> >>  arch/arm64/Kconfig.platforms    |   1 +
> >>  drivers/irqchip/Makefile        |   1 +
> >>  drivers/irqchip/irq-sun6i-r.c   | 267 ++++++++++++++++++++++++++++++++
> >>  drivers/irqchip/irq-sunxi-nmi.c |  26 +---
> >>  5 files changed, 273 insertions(+), 23 deletions(-)
> >>  create mode 100644 drivers/irqchip/irq-sun6i-r.c
> >>
> > 
> > [...]
> > 
> >> diff --git a/drivers/irqchip/irq-sun6i-r.c b/drivers/irqchip/irq-sun6i-r.c
> >> new file mode 100644
> >> index 000000000000..7490ade7b254
> >> --- /dev/null
> >> +++ b/drivers/irqchip/irq-sun6i-r.c
> >> @@ -0,0 +1,267 @@
> >> +// SPDX-License-Identifier: GPL-2.0-only
> >> +//
> >> +// R_INTC driver for Allwinner A31 and newer SoCs
> >> +//
> >> +
> >> +#include <linux/irq.h>
> >> +#include <linux/irqchip.h>
> >> +#include <linux/irqdomain.h>
> >> +#include <linux/of.h>
> >> +#include <linux/of_address.h>
> >> +#include <linux/of_irq.h>
> >> +
> >> +#include <dt-bindings/interrupt-controller/arm-gic.h>
> >> +
> >> +/*
> >> + * The R_INTC manages between 32 and 64 IRQs, divided into four groups. Example
> >> + * bit numbers are for the original variant in the A31:
> >> + *
> >> + *   Bit      0: The "External NMI" input, connected in series to a GIC SPI.
> >> + *   Bits  1-15: "Direct" IRQs for ARISC peripherals, connected in parallel to
> >> + *               the GIC and mapped 1:1 to SPIs numerically following the NMI.
> >> + *   Bits 16-18: "Banked" IRQs for peripherals that have separate interfaces
> >> + *               for the ARM CPUs and ARISC. These do not map to any GIC SPI.
> >> + *   Bits 19-31: "Muxed" IRQs, each corresponding to a group of up to 8 SPIs.
> >> + *               Later variants added a second PENDING and ENABLE register to
> >> + *               make use of all 128 mux inputs (16 IRQ lines).
> >> + *
> >> + * Since the direct IRQs are inside the muxed IRQ range, they do not increase
> >> + * the number of HWIRQs needed.
> >> + */
> >> +#define SUN6I_NR_IRQS			64
> >> +#define SUN6I_NR_DIRECT_IRQS		16
> >> +#define SUN6I_NR_MUX_INPUTS		128
> >> +#define SUN6I_NR_HWIRQS			SUN6I_NR_MUX_INPUTS
> >> +
> >> +#define SUN6I_NMI_CTRL			(0x0c)
> >> +#define SUN6I_IRQ_PENDING(n)		(0x10 + 4 * (n))
> >> +#define SUN6I_IRQ_ENABLE(n)		(0x40 + 4 * (n))
> >> +#define SUN6I_MUX_ENABLE(n)		(0xc0 + 4 * (n))
> >> +
> >> +#define SUN6I_NMI_IRQ_BIT		BIT(0)
> >> +
> >> +static void __iomem *base;
> >> +static irq_hw_number_t nmi_hwirq;
> >> +static u32 nmi_type;
> >> +
> >> +static struct irq_chip sun6i_r_intc_edge_chip;
> >> +static struct irq_chip sun6i_r_intc_level_chip;
> >> +
> >> +static void sun6i_r_intc_nmi_ack(void)
> >> +{
> >> +	/*
> >> +	 * The NMI channel has a latch separate from its trigger type.
> >> +	 * This latch must be cleared to clear the signal to the GIC.
> >> +	 */
> >> +	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_PENDING(0));
> >> +}
> >> +
> >> +static void sun6i_r_intc_irq_mask(struct irq_data *data)
> >> +{
> >> +	if (data->hwirq == nmi_hwirq)
> >> +		sun6i_r_intc_nmi_ack();
> > 
> > I'm a bit worried by this. I can see it working with level interrupts
> > (you can clear the input, and if the interrupt is asserted, it will
> > fire again), but I'm worried that it will simply result in lost
> > interrupts for edge signalling.
> 
> For edge interrupts, don't you want to ack as early as possible,
> before the handler clears the source of the interrupt? That way if a
> second interrupt comes in while you're handling the first one, you
> don't ack the second one without handling it?

It completely depends on what this block does. If, as I expect, it
latches the interrupt, then it needs clearing after the GIC has acked
the incoming interrupt.

> > It also begs the question: why would you want to clear the signal to
> > the GIC on mask (or unmask)? The expectations are that a pending
> > interrupt is preserved across a mask/unmask sequence.
> 
> I hadn't thought about anything masking the IRQ outside of the
> handler; but you're right, this breaks that case. I'm trying to work
> within the constraints of stacking the GIC driver, which assumes
> handle_fasteoi_irq, so it sounds like I should switch back to
> handle_fasteoi_ack_irq and use .irq_ack. Or based on your previous
> paragraph, maybe I'm missing some other consideration?

handle_fasteoi_ack_irq() sounds like a good match for edge
interrupts. Do you actually need to do anything for level signals? If
you do, piggybacking on .irq_eoi would do the trick.

> 
> >> +
> >> +	irq_chip_mask_parent(data);
> >> +}
> >> +
> >> +static void sun6i_r_intc_irq_unmask(struct irq_data *data)
> >> +{
> >> +	if (data->hwirq == nmi_hwirq)
> >> +		sun6i_r_intc_nmi_ack();
> >> +
> >> +	irq_chip_unmask_parent(data);
> >> +}
> >> +
> >> +static int sun6i_r_intc_irq_set_type(struct irq_data *data, unsigned int type)
> >> +{
> >> +	/*
> >> +	 * The GIC input labeled "External NMI" connects to bit 0 of the R_INTC
> >> +	 * PENDING register, not to the pin directly. So the trigger type of the
> >> +	 * GIC input does not depend on the trigger type of the NMI pin itself.
> >> +	 *
> >> +	 * Only the NMI channel is routed through this interrupt controller on
> >> +	 * its way to the GIC. Other IRQs are routed to the GIC and R_INTC in
> >> +	 * parallel; they must have a trigger type appropriate for the GIC.
> >> +	 */
> >> +	if (data->hwirq == nmi_hwirq) {
> >> +		struct irq_chip *chip;
> >> +		u32 nmi_src_type;
> >> +
> >> +		switch (type) {
> >> +		case IRQ_TYPE_LEVEL_LOW:
> >> +			chip = &sun6i_r_intc_level_chip;
> >> +			nmi_src_type = 0;
> > 
> > Please add symbolic names for these types.
> 
> I removed them based on your previous comment:
> 
> https://lkml.org/lkml/2020/1/20/278
> > It is unusual to use an enum for values that get directly programmed into the HW.
> 
> Do you want them to be specifically #defines?

Yes please.

> 
> >> +			break;
> >> +		case IRQ_TYPE_EDGE_FALLING:
> >> +			chip = &sun6i_r_intc_edge_chip;
> >> +			nmi_src_type = 1;
> >> +			break;
> >> +		case IRQ_TYPE_LEVEL_HIGH:
> >> +			chip = &sun6i_r_intc_level_chip;
> >> +			nmi_src_type = 2;
> >> +			break;
> >> +		case IRQ_TYPE_EDGE_RISING:
> >> +			chip = &sun6i_r_intc_edge_chip;
> >> +			nmi_src_type = 3;
> >> +			break;
> >> +		default:
> >> +			pr_err("%pOF: invalid trigger type %d for IRQ %d\n",
> >> +			       irq_domain_get_of_node(data->domain), type,
> >> +			       data->irq);
> > 
> > A failing set_type already triggers a kernel message.
> 
> I'll remove this.
> 
> >> +			return -EBADR;
> > 
> > That's a pretty odd error. I see it used in 3 drivers (including the
> > one this driver replaces), but the canonical error code is -EINVAL.
> 
> I'll change it to -EINVAL.
> 
> >> +		}
> >> +
> >> +		irq_set_chip_handler_name_locked(data, chip,
> >> +						 handle_fasteoi_irq, NULL);
> >> +
> >> +		writel_relaxed(nmi_src_type, base + SUN6I_NMI_CTRL);
> >> +
> >> +		/*
> >> +		 * Use the trigger type from the OF node for the NMI's
> >> +		 * R_INTC to GIC connection.
> >> +		 */
> >> +		type = nmi_type;
> > 
> > This looks wrong. The GIC only supports level-high and edge-rising, so
> > half of the possible settings will result in an error. I assume the
> > R_INTC has an inverter controlled by nmi_src_type, and only outputs
> > something the GIC can grok.
> 
> nmi_type isn't the setting from the incoming IRQ. nmi_type is from
> the interrupts property in the irqchip OF node itself. So this is a
> fwspec for `interrupt-parent = <&gic>;`, i.e. already assumed to be
> GIC-compatible. I'm not sure what you mean by "half of the possible
> settings".

Ah, I see. I misread where nmi_type was coming from. Please ignore me.

> 
> Maybe I should remove the `interrupts` property and hardcode the
> number and type connecting to the GIC? If I did that, I'm not quite
> sure whether it would be high or rising.

I guess that the output of this block is a level signal, so you should
probably enforce that.

> The output to the GIC is literally the bit in the pending register:
> 1 for pending, 0 for not. Since that is after a latch (regardless of
> the input trigger type) it sounds like it should be level-high,
> because a pulse would have already been converted to a steady
> signal. Or does it depend on when I clear the latch?

Level and edge will have different latch clearing requirements, as
outlined above. For level, it needs to be cleared after handling the
interrupt, at the point where you would deactivate it in the GIC
(.irq_eoi). For edge, that's an Ack.

[...]

> >> +static int sun6i_r_intc_domain_alloc(struct irq_domain *domain,
> >> +				     unsigned int virq,
> >> +				     unsigned int nr_irqs, void *arg)
> >> +{
> >> +	struct irq_fwspec *fwspec = arg;
> >> +	struct irq_fwspec gic_fwspec;
> >> +	unsigned long hwirq;
> >> +	unsigned int type;
> >> +	int i, ret;
> >> +
> >> +	ret = sun6i_r_intc_domain_translate(domain, fwspec, &hwirq, &type);
> >> +	if (ret)
> >> +		return ret;
> >> +	if (hwirq + nr_irqs > SUN6I_NR_HWIRQS)
> >> +		return -EINVAL;
> >> +
> >> +	/* Construct a GIC-compatible fwspec from this fwspec. */
> >> +	gic_fwspec = (struct irq_fwspec) {
> >> +		.fwnode      = domain->parent->fwnode,
> >> +		.param_count = 3,
> >> +		.param       = { GIC_SPI, hwirq, type },
> >> +	};
> >> +
> >> +	for (i = 0; i < nr_irqs; ++i)
> >> +		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
> >> +					      &sun6i_r_intc_level_chip, NULL);
> > 
> > Unconditionally level, without looking at the requested type?
> 
> __setup_irq calls __irq_set_trigger if any trigger is provided, which calls
> chip->irq_set_type unconditionally. So I don't think the chip here matters,
> because .irq_set_type will be called before the IRQ is enabled anyway. Again,
> maybe I'm missing something.

It doesn't really matter, but it is a bit odd to have the information
at hand, and ignore it. This at least deserves a comment.

> For non-NMI IRQs, the choice of chip doesn't matter, because this
> driver handles nothing but .irq_set_wake for them (should I provide
> a third chip for this that doesn't provide its own
> ack/mask/unmask?).

I think you could handle the NMI with its own single irqchip (for both
level and edge, only checking for the configuration in ack/eoi), and
have a non-NMI chip for the rest.

> 
> >> +
> >> +	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_fwspec);
> >> +}
> >> +
> >> +static const struct irq_domain_ops sun6i_r_intc_domain_ops = {
> >> +	.translate	= sun6i_r_intc_domain_translate,
> >> +	.alloc		= sun6i_r_intc_domain_alloc,
> >> +	.free		= irq_domain_free_irqs_common,
> >> +};
> >> +
> >> +static void sun6i_r_intc_resume(void)
> >> +{
> >> +	int i;
> >> +
> >> +	/* Only the NMI is relevant during normal operation. */
> >> +	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_ENABLE(0));
> >> +	for (i = 1; i < BITS_TO_U32(SUN6I_NR_IRQS); ++i)
> >> +		writel_relaxed(0, base + SUN6I_IRQ_ENABLE(i));
> > 
> > If only the NMI is relevant, why are the other interrupts enabled?
> > Shouldn't this be moved to the following patch (I presume this is
> > wake-up related...).
> 
> The other IRQs aren't enabled? I'm writing all zeroes to the enable register.

Duh. -ECANTREAD.

> >> +}
> >> +
> >> +static int __init sun6i_r_intc_init(struct device_node *node,
> >> +				    struct device_node *parent)
> >> +{
> >> +	struct irq_domain *domain, *parent_domain;
> >> +	struct of_phandle_args parent_irq;
> >> +	int ret;
> >> +
> >> +	/* Extract the NMI's R_INTC to GIC mapping from the OF node. */
> >> +	ret = of_irq_parse_one(node, 0, &parent_irq);
> >> +	if (ret)
> >> +		return ret;
> >> +	if (parent_irq.args_count < 3 || parent_irq.args[0] != GIC_SPI)
> >> +		return -EINVAL;
> >> +	nmi_hwirq = parent_irq.args[1];
> >> +	nmi_type = parent_irq.args[2];
> > 
> > This looks a lot like the translate callback.
> 
> Yes, I could use that here.
> 
> >> +
> >> +	parent_domain = irq_find_host(parent);
> >> +	if (!parent_domain) {
> >> +		pr_err("%pOF: Failed to obtain parent domain\n", node);
> >> +		return -ENXIO;
> >> +	}
> >> +
> >> +	base = of_io_request_and_map(node, 0, NULL);
> >> +	if (IS_ERR(base)) {
> >> +		pr_err("%pOF: Failed to map MMIO region\n", node);
> >> +		return PTR_ERR(base);
> >> +	}
> >> +
> >> +	sun6i_r_intc_nmi_ack();
> >> +	sun6i_r_intc_resume();
> >> +
> >> +	domain = irq_domain_add_hierarchy(parent_domain, 0,
> >> +					  SUN6I_NR_HWIRQS, node,
> >> +					  &sun6i_r_intc_domain_ops, NULL);
> >> +	if (!domain) {
> >> +		pr_err("%pOF: Failed to allocate domain\n", node);
> >> +		iounmap(base);
> >> +		return -ENOMEM;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +IRQCHIP_DECLARE(sun6i_r_intc, "allwinner,sun6i-a31-r-intc", sun6i_r_intc_init);
> > 
> > Thanks,
> > 
> > 	M.
> > 
> 
> Thank you for your (extremely quick, I must say) review!

Locked up home until Wednesday. I try to keep myself busy...

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 03/10] irqchip/sun6i-r: Use a stacked irqchip driver
  2021-01-03 13:10         ` Marc Zyngier
@ 2021-01-04  3:46           ` Samuel Holland
  -1 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-04  3:46 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Thomas Gleixner, Rob Herring, Maxime Ripard, Chen-Yu Tsai,
	Jernej Skrabec, Russell King, Catalin Marinas, Will Deacon,
	Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel

On 1/3/21 7:10 AM, Marc Zyngier wrote:
> On Sun, 03 Jan 2021 12:08:43 +0000,
> Samuel Holland <samuel@sholland.org> wrote:
>>
>> On 1/3/21 5:27 AM, Marc Zyngier wrote:
>>> On Sun, 03 Jan 2021 10:30:54 +0000,
>>> Samuel Holland <samuel@sholland.org> wrote:
>>>>
>>>> The R_INTC in the A31 and newer sun8i/sun50i SoCs is more similar to the
>>>> original sun4i interrupt controller than the sun7i/sun9i NMI controller.
>>>> It is used for two distinct purposes:
>>>>  - To control the trigger, latch, and mask for the NMI input pin
>>>>  - To provide the interrupt input for the ARISC coprocessor
>>>>
>>>> As this interrupt controller is not documented, information about it
>>>> comes from vendor-provided firmware blobs and from experimentation.
>>>>
>>>> Like the original sun4i interrupt controller, it has:
>>>>  - A VECTOR_REG at 0x00 (configurable via the BASE_ADDR_REG at 0x04)
>>>>  - A NMI_CTRL_REG, PENDING_REG, and ENABLE_REG as used by both the
>>>>    sun4i and sunxi-nmi drivers
>>>>  - A MASK_REG at 0x50
>>>>  - A RESP_REG at 0x60
>>>>
>>>> Differences from the sun4i interrupt controller appear to be:
>>>>  - It only has one or two registers of each kind (max 32 or 64 IRQs)
>>>>  - Multiplexing logic is added to support additional inputs
>>>>  - There is no FIQ-related logic
>>>>  - There is no interrupt priority logic
>>>>
>>>> In order to fulfill its two purposes, this hardware block combines four
>>>> types of IRQs. First, the NMI pin is routed to the "IRQ 0" input on this
>>>> chip, with a trigger type controlled by the NMI_CTRL_REG. The "IRQ 0
>>>> pending" output from this chip, if enabled, is then routed to a SPI IRQ
>>>> input on the GIC. In other words, bit 0 of IRQ_ENABLE_REG *does* affect
>>>> the NMI IRQ seen at the GIC.
>>>>
>>>> The NMI is followed by a contiguous block of 15 "direct" (my name for
>>>> them) IRQ inputs that are connected in parallel to both R_INTC and the
>>>> GIC. Or in other words, these bits of IRQ_ENABLE_REG *do not* affect the
>>>> IRQs seen at the GIC.
>>>>
>>>> Following the direct IRQs are the ARISC's copy of banked IRQs for shared
>>>> peripherals. These are not relevant to Linux. The remaining IRQs are
>>>> connected to a multiplexer and provide access to the first (up to) 128
>>>> SPIs from the ARISC. This range of SPIs overlaps with the direct IRQs.
>>>>
>>>> Finally, the global "IRQ pending" output from R_INTC, after being masked
>>>> by MASK_REG and RESP_REG, is connected to the "external interrupt" input
>>>> of the ARISC CPU. This path is also irrelevant to Linux.
>>>
>>> An ASCII-art version of this would help a lot, and would look good in
>>> the driver code...
>>
>> There is this diagram which I forgot to include in the cover letter:
>>
>>   https://linux-sunxi.org/images/5/5c/R_INTC.png
>>
>> I can try to come up with some ASCII art.
>>
>>>> Because of the 1:1 correspondence between R_INTC and GIC inputs, this is
>>>> a perfect scenario for using a stacked irqchip driver. We want to hook
>>>> into enabling/disabling IRQs to add more features to the GIC
>>>> (specifically to allow masking the NMI and setting its trigger type),
>>>> but we don't need to actually handle the IRQ in this driver.
>>>>
>>>> And since R_INTC is in the always-on power domain, and its output is
>>>> connected directly in to the power management coprocessor, a stacked
>>>> irqchip driver provides a simple way to add wakeup support to this set
>>>> of IRQs. That is the next patch; for now, just the NMI is moved over.
>>>>
>>>> To allow access to all multiplexed IRQs, this driver requires a new
>>>> binding where the interrupt number matches the GIC interrupt number.
>>>> (This moves the NMI number from 0 to 32 or 96, depending on the SoC.)
>>>> For simplicity, copy the three-cell GIC binding; this disambiguates
>>>> interrupt 0 in the old binding (the NMI) from interrupt 0 in the new
>>>> binding (SPI 0) by the number of cells.
>>>>
>>>> This commit mostly reverts commit 173bda53b340 ("irqchip/sunxi-nmi:
>>>> Support sun6i-a31-r-intc compatible").
>>>>
>>>> Signed-off-by: Samuel Holland <samuel@sholland.org>
>>>> ---
>>>>  arch/arm/mach-sunxi/Kconfig     |   1 +
>>>>  arch/arm64/Kconfig.platforms    |   1 +
>>>>  drivers/irqchip/Makefile        |   1 +
>>>>  drivers/irqchip/irq-sun6i-r.c   | 267 ++++++++++++++++++++++++++++++++
>>>>  drivers/irqchip/irq-sunxi-nmi.c |  26 +---
>>>>  5 files changed, 273 insertions(+), 23 deletions(-)
>>>>  create mode 100644 drivers/irqchip/irq-sun6i-r.c
>>>>
>>>
>>> [...]
>>>
>>>> diff --git a/drivers/irqchip/irq-sun6i-r.c b/drivers/irqchip/irq-sun6i-r.c
>>>> new file mode 100644
>>>> index 000000000000..7490ade7b254
>>>> --- /dev/null
>>>> +++ b/drivers/irqchip/irq-sun6i-r.c
>>>> @@ -0,0 +1,267 @@
>>>> +// SPDX-License-Identifier: GPL-2.0-only
>>>> +//
>>>> +// R_INTC driver for Allwinner A31 and newer SoCs
>>>> +//
>>>> +
>>>> +#include <linux/irq.h>
>>>> +#include <linux/irqchip.h>
>>>> +#include <linux/irqdomain.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/of_address.h>
>>>> +#include <linux/of_irq.h>
>>>> +
>>>> +#include <dt-bindings/interrupt-controller/arm-gic.h>
>>>> +
>>>> +/*
>>>> + * The R_INTC manages between 32 and 64 IRQs, divided into four groups. Example
>>>> + * bit numbers are for the original variant in the A31:
>>>> + *
>>>> + *   Bit      0: The "External NMI" input, connected in series to a GIC SPI.
>>>> + *   Bits  1-15: "Direct" IRQs for ARISC peripherals, connected in parallel to
>>>> + *               the GIC and mapped 1:1 to SPIs numerically following the NMI.
>>>> + *   Bits 16-18: "Banked" IRQs for peripherals that have separate interfaces
>>>> + *               for the ARM CPUs and ARISC. These do not map to any GIC SPI.
>>>> + *   Bits 19-31: "Muxed" IRQs, each corresponding to a group of up to 8 SPIs.
>>>> + *               Later variants added a second PENDING and ENABLE register to
>>>> + *               make use of all 128 mux inputs (16 IRQ lines).
>>>> + *
>>>> + * Since the direct IRQs are inside the muxed IRQ range, they do not increase
>>>> + * the number of HWIRQs needed.
>>>> + */
>>>> +#define SUN6I_NR_IRQS			64
>>>> +#define SUN6I_NR_DIRECT_IRQS		16
>>>> +#define SUN6I_NR_MUX_INPUTS		128
>>>> +#define SUN6I_NR_HWIRQS			SUN6I_NR_MUX_INPUTS
>>>> +
>>>> +#define SUN6I_NMI_CTRL			(0x0c)
>>>> +#define SUN6I_IRQ_PENDING(n)		(0x10 + 4 * (n))
>>>> +#define SUN6I_IRQ_ENABLE(n)		(0x40 + 4 * (n))
>>>> +#define SUN6I_MUX_ENABLE(n)		(0xc0 + 4 * (n))
>>>> +
>>>> +#define SUN6I_NMI_IRQ_BIT		BIT(0)
>>>> +
>>>> +static void __iomem *base;
>>>> +static irq_hw_number_t nmi_hwirq;
>>>> +static u32 nmi_type;
>>>> +
>>>> +static struct irq_chip sun6i_r_intc_edge_chip;
>>>> +static struct irq_chip sun6i_r_intc_level_chip;
>>>> +
>>>> +static void sun6i_r_intc_nmi_ack(void)
>>>> +{
>>>> +	/*
>>>> +	 * The NMI channel has a latch separate from its trigger type.
>>>> +	 * This latch must be cleared to clear the signal to the GIC.
>>>> +	 */
>>>> +	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_PENDING(0));
>>>> +}
>>>> +
>>>> +static void sun6i_r_intc_irq_mask(struct irq_data *data)
>>>> +{
>>>> +	if (data->hwirq == nmi_hwirq)
>>>> +		sun6i_r_intc_nmi_ack();
>>>
>>> I'm a bit worried by this. I can see it working with level interrupts
>>> (you can clear the input, and if the interrupt is asserted, it will
>>> fire again), but I'm worried that it will simply result in lost
>>> interrupts for edge signalling.
>>
>> For edge interrupts, don't you want to ack as early as possible,
>> before the handler clears the source of the interrupt? That way if a
>> second interrupt comes in while you're handling the first one, you
>> don't ack the second one without handling it?
> 
> It completely depends on what this block does. If, as I expect, it
> latches the interrupt, then it needs clearing after the GIC has acked
> the incoming interrupt.

Yes, there is an internal S/R latch.
 - For edge interrupts, the latch is set once for each pulse.
 - For level interrupts, it gets set continuously as long as the
   pin is high/low.
 - Writing a "1" to bit 0 of PENDING resets the latch.
 - The output of the latch goes to the GIC.

>>> It also begs the question: why would you want to clear the signal to
>>> the GIC on mask (or unmask)? The expectations are that a pending
>>> interrupt is preserved across a mask/unmask sequence.
>>
>> I hadn't thought about anything masking the IRQ outside of the
>> handler; but you're right, this breaks that case. I'm trying to work
>> within the constraints of stacking the GIC driver, which assumes
>> handle_fasteoi_irq, so it sounds like I should switch back to
>> handle_fasteoi_ack_irq and use .irq_ack. Or based on your previous
>> paragraph, maybe I'm missing some other consideration?
> 
> handle_fasteoi_ack_irq() sounds like a good match for edge
> interrupts. Do you actually need to do anything for level signals? If
> you do, piggybacking on .irq_eoi would do the trick.

For level interrupts, I have to reset the latch (see above) after the source of
the interrupt is cleared.

That was the bug with v2: I set IRQ_EOI_THREADED so .irq_eoi would run after the
thread. But with GICv2 EOImode==0, that blocked other interrupts from being
received during the IRQ thread. Which is why I moved it to .irq_unmask and
removed the flag: so .irq_eoi runs at the end of the hardirq (unblocking further
interrupts at the GIC), and .irq_unmask resets the latch at the end of the thread.

With the flag removed, but still clearing the latch in .irq_eoi, every edge IRQ
was followed by a second, spurious IRQ after the thread finished.

Does that make sense?

>>>> +
>>>> +	irq_chip_mask_parent(data);
>>>> +}
>>>> +
>>>> +static void sun6i_r_intc_irq_unmask(struct irq_data *data)
>>>> +{
>>>> +	if (data->hwirq == nmi_hwirq)
>>>> +		sun6i_r_intc_nmi_ack();
>>>> +
>>>> +	irq_chip_unmask_parent(data);
>>>> +}
>>>> +
>>>> +static int sun6i_r_intc_irq_set_type(struct irq_data *data, unsigned int type)
>>>> +{
>>>> +	/*
>>>> +	 * The GIC input labeled "External NMI" connects to bit 0 of the R_INTC
>>>> +	 * PENDING register, not to the pin directly. So the trigger type of the
>>>> +	 * GIC input does not depend on the trigger type of the NMI pin itself.
>>>> +	 *
>>>> +	 * Only the NMI channel is routed through this interrupt controller on
>>>> +	 * its way to the GIC. Other IRQs are routed to the GIC and R_INTC in
>>>> +	 * parallel; they must have a trigger type appropriate for the GIC.
>>>> +	 */
>>>> +	if (data->hwirq == nmi_hwirq) {
>>>> +		struct irq_chip *chip;
>>>> +		u32 nmi_src_type;
>>>> +
>>>> +		switch (type) {
>>>> +		case IRQ_TYPE_LEVEL_LOW:
>>>> +			chip = &sun6i_r_intc_level_chip;
>>>> +			nmi_src_type = 0;
>>>
>>> Please add symbolic names for these types.
>>
>> I removed them based on your previous comment:
>>
>> https://lkml.org/lkml/2020/1/20/278
>>> It is unusual to use an enum for values that get directly programmed into the HW.
>>
>> Do you want them to be specifically #defines?
> 
> Yes please.

Will do.

>>
>>>> +			break;
>>>> +		case IRQ_TYPE_EDGE_FALLING:
>>>> +			chip = &sun6i_r_intc_edge_chip;
>>>> +			nmi_src_type = 1;
>>>> +			break;
>>>> +		case IRQ_TYPE_LEVEL_HIGH:
>>>> +			chip = &sun6i_r_intc_level_chip;
>>>> +			nmi_src_type = 2;
>>>> +			break;
>>>> +		case IRQ_TYPE_EDGE_RISING:
>>>> +			chip = &sun6i_r_intc_edge_chip;
>>>> +			nmi_src_type = 3;
>>>> +			break;
>>>> +		default:
>>>> +			pr_err("%pOF: invalid trigger type %d for IRQ %d\n",
>>>> +			       irq_domain_get_of_node(data->domain), type,
>>>> +			       data->irq);
>>>
>>> A failing set_type already triggers a kernel message.
>>
>> I'll remove this.
>>
>>>> +			return -EBADR;
>>>
>>> That's a pretty odd error. I see it used in 3 drivers (including the
>>> one this driver replaces), but the canonical error code is -EINVAL.
>>
>> I'll change it to -EINVAL.
>>
>>>> +		}
>>>> +
>>>> +		irq_set_chip_handler_name_locked(data, chip,
>>>> +						 handle_fasteoi_irq, NULL);
>>>> +
>>>> +		writel_relaxed(nmi_src_type, base + SUN6I_NMI_CTRL);
>>>> +
>>>> +		/*
>>>> +		 * Use the trigger type from the OF node for the NMI's
>>>> +		 * R_INTC to GIC connection.
>>>> +		 */
>>>> +		type = nmi_type;
>>>
>>> This looks wrong. The GIC only supports level-high and edge-rising, so
>>> half of the possible settings will result in an error. I assume the
>>> R_INTC has an inverter controlled by nmi_src_type, and only outputs
>>> something the GIC can grok.
>>
>> nmi_type isn't the setting from the incoming IRQ. nmi_type is from
>> the interrupts property in the irqchip OF node itself. So this is a
>> fwspec for `interrupt-parent = <&gic>;`, i.e. already assumed to be
>> GIC-compatible. I'm not sure what you mean by "half of the possible
>> settings".
> 
> Ah, I see. I misread where nmi_type was coming from. Please ignore me.
> 
>>
>> Maybe I should remove the `interrupts` property and hardcode the
>> number and type connecting to the GIC? If I did that, I'm not quite
>> sure whether it would be high or rising.
> 
> I guess that the output of this block is a level signal, so you should
> probably enforce that.

Okay, I'll do that.

>> The output to the GIC is literally the bit in the pending register:
>> 1 for pending, 0 for not. Since that is after a latch (regardless of
>> the input trigger type) it sounds like it should be level-high,
>> because a pulse would have already been converted to a steady
>> signal. Or does it depend on when I clear the latch?
> 
> Level and edge will have different latch clearing requirements, as
> outlined above. For level, it needs to be cleared after handling the
> interrupt, at the point where you would deactivate it in the GIC
> (.irq_eoi). For edge, that's an Ack.
> 
> [...]
> 
>>>> +static int sun6i_r_intc_domain_alloc(struct irq_domain *domain,
>>>> +				     unsigned int virq,
>>>> +				     unsigned int nr_irqs, void *arg)
>>>> +{
>>>> +	struct irq_fwspec *fwspec = arg;
>>>> +	struct irq_fwspec gic_fwspec;
>>>> +	unsigned long hwirq;
>>>> +	unsigned int type;
>>>> +	int i, ret;
>>>> +
>>>> +	ret = sun6i_r_intc_domain_translate(domain, fwspec, &hwirq, &type);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +	if (hwirq + nr_irqs > SUN6I_NR_HWIRQS)
>>>> +		return -EINVAL;
>>>> +
>>>> +	/* Construct a GIC-compatible fwspec from this fwspec. */
>>>> +	gic_fwspec = (struct irq_fwspec) {
>>>> +		.fwnode      = domain->parent->fwnode,
>>>> +		.param_count = 3,
>>>> +		.param       = { GIC_SPI, hwirq, type },
>>>> +	};
>>>> +
>>>> +	for (i = 0; i < nr_irqs; ++i)
>>>> +		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
>>>> +					      &sun6i_r_intc_level_chip, NULL);
>>>
>>> Unconditionally level, without looking at the requested type?
>>
>> __setup_irq calls __irq_set_trigger if any trigger is provided, which calls
>> chip->irq_set_type unconditionally. So I don't think the chip here matters,
>> because .irq_set_type will be called before the IRQ is enabled anyway. Again,
>> maybe I'm missing something.
> 
> It doesn't really matter, but it is a bit odd to have the information
> at hand, and ignore it. This at least deserves a comment.
> 
>> For non-NMI IRQs, the choice of chip doesn't matter, because this
>> driver handles nothing but .irq_set_wake for them (should I provide
>> a third chip for this that doesn't provide its own
>> ack/mask/unmask?).
> 
> I think you could handle the NMI with its own single irqchip (for both
> level and edge, only checking for the configuration in ack/eoi), and
> have a non-NMI chip for the rest.

I will try that.

>>
>>>> +
>>>> +	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_fwspec);
>>>> +}
>>>> +
>>>> +static const struct irq_domain_ops sun6i_r_intc_domain_ops = {
>>>> +	.translate	= sun6i_r_intc_domain_translate,
>>>> +	.alloc		= sun6i_r_intc_domain_alloc,
>>>> +	.free		= irq_domain_free_irqs_common,
>>>> +};
>>>> +
>>>> +static void sun6i_r_intc_resume(void)
>>>> +{
>>>> +	int i;
>>>> +
>>>> +	/* Only the NMI is relevant during normal operation. */
>>>> +	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_ENABLE(0));
>>>> +	for (i = 1; i < BITS_TO_U32(SUN6I_NR_IRQS); ++i)
>>>> +		writel_relaxed(0, base + SUN6I_IRQ_ENABLE(i));
>>>
>>> If only the NMI is relevant, why are the other interrupts enabled?
>>> Shouldn't this be moved to the following patch (I presume this is
>>> wake-up related...).
>>
>> The other IRQs aren't enabled? I'm writing all zeroes to the enable register.
> 
> Duh. -ECANTREAD.
> 
>>>> +}
>>>> +
>>>> +static int __init sun6i_r_intc_init(struct device_node *node,
>>>> +				    struct device_node *parent)
>>>> +{
>>>> +	struct irq_domain *domain, *parent_domain;
>>>> +	struct of_phandle_args parent_irq;
>>>> +	int ret;
>>>> +
>>>> +	/* Extract the NMI's R_INTC to GIC mapping from the OF node. */
>>>> +	ret = of_irq_parse_one(node, 0, &parent_irq);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +	if (parent_irq.args_count < 3 || parent_irq.args[0] != GIC_SPI)
>>>> +		return -EINVAL;
>>>> +	nmi_hwirq = parent_irq.args[1];
>>>> +	nmi_type = parent_irq.args[2];
>>>
>>> This looks a lot like the translate callback.
>>
>> Yes, I could use that here.
>>
>>>> +
>>>> +	parent_domain = irq_find_host(parent);
>>>> +	if (!parent_domain) {
>>>> +		pr_err("%pOF: Failed to obtain parent domain\n", node);
>>>> +		return -ENXIO;
>>>> +	}
>>>> +
>>>> +	base = of_io_request_and_map(node, 0, NULL);
>>>> +	if (IS_ERR(base)) {
>>>> +		pr_err("%pOF: Failed to map MMIO region\n", node);
>>>> +		return PTR_ERR(base);
>>>> +	}
>>>> +
>>>> +	sun6i_r_intc_nmi_ack();
>>>> +	sun6i_r_intc_resume();
>>>> +
>>>> +	domain = irq_domain_add_hierarchy(parent_domain, 0,
>>>> +					  SUN6I_NR_HWIRQS, node,
>>>> +					  &sun6i_r_intc_domain_ops, NULL);
>>>> +	if (!domain) {
>>>> +		pr_err("%pOF: Failed to allocate domain\n", node);
>>>> +		iounmap(base);
>>>> +		return -ENOMEM;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +IRQCHIP_DECLARE(sun6i_r_intc, "allwinner,sun6i-a31-r-intc", sun6i_r_intc_init);
>>>
>>> Thanks,
>>>
>>> 	M.
>>>
>>
>> Thank you for your (extremely quick, I must say) review!
> 
> Locked up home until Wednesday. I try to keep myself busy...
> 
> Thanks,
> 
> 	M.
> 

Thanks,
Samuel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 03/10] irqchip/sun6i-r: Use a stacked irqchip driver
@ 2021-01-04  3:46           ` Samuel Holland
  0 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-04  3:46 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Ondrej Jirman, devicetree, Jernej Skrabec, Catalin Marinas,
	Russell King, Maxime Ripard, linux-kernel, Chen-Yu Tsai,
	Rob Herring, Thomas Gleixner, Will Deacon, linux-arm-kernel

On 1/3/21 7:10 AM, Marc Zyngier wrote:
> On Sun, 03 Jan 2021 12:08:43 +0000,
> Samuel Holland <samuel@sholland.org> wrote:
>>
>> On 1/3/21 5:27 AM, Marc Zyngier wrote:
>>> On Sun, 03 Jan 2021 10:30:54 +0000,
>>> Samuel Holland <samuel@sholland.org> wrote:
>>>>
>>>> The R_INTC in the A31 and newer sun8i/sun50i SoCs is more similar to the
>>>> original sun4i interrupt controller than the sun7i/sun9i NMI controller.
>>>> It is used for two distinct purposes:
>>>>  - To control the trigger, latch, and mask for the NMI input pin
>>>>  - To provide the interrupt input for the ARISC coprocessor
>>>>
>>>> As this interrupt controller is not documented, information about it
>>>> comes from vendor-provided firmware blobs and from experimentation.
>>>>
>>>> Like the original sun4i interrupt controller, it has:
>>>>  - A VECTOR_REG at 0x00 (configurable via the BASE_ADDR_REG at 0x04)
>>>>  - A NMI_CTRL_REG, PENDING_REG, and ENABLE_REG as used by both the
>>>>    sun4i and sunxi-nmi drivers
>>>>  - A MASK_REG at 0x50
>>>>  - A RESP_REG at 0x60
>>>>
>>>> Differences from the sun4i interrupt controller appear to be:
>>>>  - It only has one or two registers of each kind (max 32 or 64 IRQs)
>>>>  - Multiplexing logic is added to support additional inputs
>>>>  - There is no FIQ-related logic
>>>>  - There is no interrupt priority logic
>>>>
>>>> In order to fulfill its two purposes, this hardware block combines four
>>>> types of IRQs. First, the NMI pin is routed to the "IRQ 0" input on this
>>>> chip, with a trigger type controlled by the NMI_CTRL_REG. The "IRQ 0
>>>> pending" output from this chip, if enabled, is then routed to a SPI IRQ
>>>> input on the GIC. In other words, bit 0 of IRQ_ENABLE_REG *does* affect
>>>> the NMI IRQ seen at the GIC.
>>>>
>>>> The NMI is followed by a contiguous block of 15 "direct" (my name for
>>>> them) IRQ inputs that are connected in parallel to both R_INTC and the
>>>> GIC. Or in other words, these bits of IRQ_ENABLE_REG *do not* affect the
>>>> IRQs seen at the GIC.
>>>>
>>>> Following the direct IRQs are the ARISC's copy of banked IRQs for shared
>>>> peripherals. These are not relevant to Linux. The remaining IRQs are
>>>> connected to a multiplexer and provide access to the first (up to) 128
>>>> SPIs from the ARISC. This range of SPIs overlaps with the direct IRQs.
>>>>
>>>> Finally, the global "IRQ pending" output from R_INTC, after being masked
>>>> by MASK_REG and RESP_REG, is connected to the "external interrupt" input
>>>> of the ARISC CPU. This path is also irrelevant to Linux.
>>>
>>> An ASCII-art version of this would help a lot, and would look good in
>>> the driver code...
>>
>> There is this diagram which I forgot to include in the cover letter:
>>
>>   https://linux-sunxi.org/images/5/5c/R_INTC.png
>>
>> I can try to come up with some ASCII art.
>>
>>>> Because of the 1:1 correspondence between R_INTC and GIC inputs, this is
>>>> a perfect scenario for using a stacked irqchip driver. We want to hook
>>>> into enabling/disabling IRQs to add more features to the GIC
>>>> (specifically to allow masking the NMI and setting its trigger type),
>>>> but we don't need to actually handle the IRQ in this driver.
>>>>
>>>> And since R_INTC is in the always-on power domain, and its output is
>>>> connected directly in to the power management coprocessor, a stacked
>>>> irqchip driver provides a simple way to add wakeup support to this set
>>>> of IRQs. That is the next patch; for now, just the NMI is moved over.
>>>>
>>>> To allow access to all multiplexed IRQs, this driver requires a new
>>>> binding where the interrupt number matches the GIC interrupt number.
>>>> (This moves the NMI number from 0 to 32 or 96, depending on the SoC.)
>>>> For simplicity, copy the three-cell GIC binding; this disambiguates
>>>> interrupt 0 in the old binding (the NMI) from interrupt 0 in the new
>>>> binding (SPI 0) by the number of cells.
>>>>
>>>> This commit mostly reverts commit 173bda53b340 ("irqchip/sunxi-nmi:
>>>> Support sun6i-a31-r-intc compatible").
>>>>
>>>> Signed-off-by: Samuel Holland <samuel@sholland.org>
>>>> ---
>>>>  arch/arm/mach-sunxi/Kconfig     |   1 +
>>>>  arch/arm64/Kconfig.platforms    |   1 +
>>>>  drivers/irqchip/Makefile        |   1 +
>>>>  drivers/irqchip/irq-sun6i-r.c   | 267 ++++++++++++++++++++++++++++++++
>>>>  drivers/irqchip/irq-sunxi-nmi.c |  26 +---
>>>>  5 files changed, 273 insertions(+), 23 deletions(-)
>>>>  create mode 100644 drivers/irqchip/irq-sun6i-r.c
>>>>
>>>
>>> [...]
>>>
>>>> diff --git a/drivers/irqchip/irq-sun6i-r.c b/drivers/irqchip/irq-sun6i-r.c
>>>> new file mode 100644
>>>> index 000000000000..7490ade7b254
>>>> --- /dev/null
>>>> +++ b/drivers/irqchip/irq-sun6i-r.c
>>>> @@ -0,0 +1,267 @@
>>>> +// SPDX-License-Identifier: GPL-2.0-only
>>>> +//
>>>> +// R_INTC driver for Allwinner A31 and newer SoCs
>>>> +//
>>>> +
>>>> +#include <linux/irq.h>
>>>> +#include <linux/irqchip.h>
>>>> +#include <linux/irqdomain.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/of_address.h>
>>>> +#include <linux/of_irq.h>
>>>> +
>>>> +#include <dt-bindings/interrupt-controller/arm-gic.h>
>>>> +
>>>> +/*
>>>> + * The R_INTC manages between 32 and 64 IRQs, divided into four groups. Example
>>>> + * bit numbers are for the original variant in the A31:
>>>> + *
>>>> + *   Bit      0: The "External NMI" input, connected in series to a GIC SPI.
>>>> + *   Bits  1-15: "Direct" IRQs for ARISC peripherals, connected in parallel to
>>>> + *               the GIC and mapped 1:1 to SPIs numerically following the NMI.
>>>> + *   Bits 16-18: "Banked" IRQs for peripherals that have separate interfaces
>>>> + *               for the ARM CPUs and ARISC. These do not map to any GIC SPI.
>>>> + *   Bits 19-31: "Muxed" IRQs, each corresponding to a group of up to 8 SPIs.
>>>> + *               Later variants added a second PENDING and ENABLE register to
>>>> + *               make use of all 128 mux inputs (16 IRQ lines).
>>>> + *
>>>> + * Since the direct IRQs are inside the muxed IRQ range, they do not increase
>>>> + * the number of HWIRQs needed.
>>>> + */
>>>> +#define SUN6I_NR_IRQS			64
>>>> +#define SUN6I_NR_DIRECT_IRQS		16
>>>> +#define SUN6I_NR_MUX_INPUTS		128
>>>> +#define SUN6I_NR_HWIRQS			SUN6I_NR_MUX_INPUTS
>>>> +
>>>> +#define SUN6I_NMI_CTRL			(0x0c)
>>>> +#define SUN6I_IRQ_PENDING(n)		(0x10 + 4 * (n))
>>>> +#define SUN6I_IRQ_ENABLE(n)		(0x40 + 4 * (n))
>>>> +#define SUN6I_MUX_ENABLE(n)		(0xc0 + 4 * (n))
>>>> +
>>>> +#define SUN6I_NMI_IRQ_BIT		BIT(0)
>>>> +
>>>> +static void __iomem *base;
>>>> +static irq_hw_number_t nmi_hwirq;
>>>> +static u32 nmi_type;
>>>> +
>>>> +static struct irq_chip sun6i_r_intc_edge_chip;
>>>> +static struct irq_chip sun6i_r_intc_level_chip;
>>>> +
>>>> +static void sun6i_r_intc_nmi_ack(void)
>>>> +{
>>>> +	/*
>>>> +	 * The NMI channel has a latch separate from its trigger type.
>>>> +	 * This latch must be cleared to clear the signal to the GIC.
>>>> +	 */
>>>> +	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_PENDING(0));
>>>> +}
>>>> +
>>>> +static void sun6i_r_intc_irq_mask(struct irq_data *data)
>>>> +{
>>>> +	if (data->hwirq == nmi_hwirq)
>>>> +		sun6i_r_intc_nmi_ack();
>>>
>>> I'm a bit worried by this. I can see it working with level interrupts
>>> (you can clear the input, and if the interrupt is asserted, it will
>>> fire again), but I'm worried that it will simply result in lost
>>> interrupts for edge signalling.
>>
>> For edge interrupts, don't you want to ack as early as possible,
>> before the handler clears the source of the interrupt? That way if a
>> second interrupt comes in while you're handling the first one, you
>> don't ack the second one without handling it?
> 
> It completely depends on what this block does. If, as I expect, it
> latches the interrupt, then it needs clearing after the GIC has acked
> the incoming interrupt.

Yes, there is an internal S/R latch.
 - For edge interrupts, the latch is set once for each pulse.
 - For level interrupts, it gets set continuously as long as the
   pin is high/low.
 - Writing a "1" to bit 0 of PENDING resets the latch.
 - The output of the latch goes to the GIC.

>>> It also begs the question: why would you want to clear the signal to
>>> the GIC on mask (or unmask)? The expectations are that a pending
>>> interrupt is preserved across a mask/unmask sequence.
>>
>> I hadn't thought about anything masking the IRQ outside of the
>> handler; but you're right, this breaks that case. I'm trying to work
>> within the constraints of stacking the GIC driver, which assumes
>> handle_fasteoi_irq, so it sounds like I should switch back to
>> handle_fasteoi_ack_irq and use .irq_ack. Or based on your previous
>> paragraph, maybe I'm missing some other consideration?
> 
> handle_fasteoi_ack_irq() sounds like a good match for edge
> interrupts. Do you actually need to do anything for level signals? If
> you do, piggybacking on .irq_eoi would do the trick.

For level interrupts, I have to reset the latch (see above) after the source of
the interrupt is cleared.

That was the bug with v2: I set IRQ_EOI_THREADED so .irq_eoi would run after the
thread. But with GICv2 EOImode==0, that blocked other interrupts from being
received during the IRQ thread. Which is why I moved it to .irq_unmask and
removed the flag: so .irq_eoi runs at the end of the hardirq (unblocking further
interrupts at the GIC), and .irq_unmask resets the latch at the end of the thread.

With the flag removed, but still clearing the latch in .irq_eoi, every edge IRQ
was followed by a second, spurious IRQ after the thread finished.

Does that make sense?

>>>> +
>>>> +	irq_chip_mask_parent(data);
>>>> +}
>>>> +
>>>> +static void sun6i_r_intc_irq_unmask(struct irq_data *data)
>>>> +{
>>>> +	if (data->hwirq == nmi_hwirq)
>>>> +		sun6i_r_intc_nmi_ack();
>>>> +
>>>> +	irq_chip_unmask_parent(data);
>>>> +}
>>>> +
>>>> +static int sun6i_r_intc_irq_set_type(struct irq_data *data, unsigned int type)
>>>> +{
>>>> +	/*
>>>> +	 * The GIC input labeled "External NMI" connects to bit 0 of the R_INTC
>>>> +	 * PENDING register, not to the pin directly. So the trigger type of the
>>>> +	 * GIC input does not depend on the trigger type of the NMI pin itself.
>>>> +	 *
>>>> +	 * Only the NMI channel is routed through this interrupt controller on
>>>> +	 * its way to the GIC. Other IRQs are routed to the GIC and R_INTC in
>>>> +	 * parallel; they must have a trigger type appropriate for the GIC.
>>>> +	 */
>>>> +	if (data->hwirq == nmi_hwirq) {
>>>> +		struct irq_chip *chip;
>>>> +		u32 nmi_src_type;
>>>> +
>>>> +		switch (type) {
>>>> +		case IRQ_TYPE_LEVEL_LOW:
>>>> +			chip = &sun6i_r_intc_level_chip;
>>>> +			nmi_src_type = 0;
>>>
>>> Please add symbolic names for these types.
>>
>> I removed them based on your previous comment:
>>
>> https://lkml.org/lkml/2020/1/20/278
>>> It is unusual to use an enum for values that get directly programmed into the HW.
>>
>> Do you want them to be specifically #defines?
> 
> Yes please.

Will do.

>>
>>>> +			break;
>>>> +		case IRQ_TYPE_EDGE_FALLING:
>>>> +			chip = &sun6i_r_intc_edge_chip;
>>>> +			nmi_src_type = 1;
>>>> +			break;
>>>> +		case IRQ_TYPE_LEVEL_HIGH:
>>>> +			chip = &sun6i_r_intc_level_chip;
>>>> +			nmi_src_type = 2;
>>>> +			break;
>>>> +		case IRQ_TYPE_EDGE_RISING:
>>>> +			chip = &sun6i_r_intc_edge_chip;
>>>> +			nmi_src_type = 3;
>>>> +			break;
>>>> +		default:
>>>> +			pr_err("%pOF: invalid trigger type %d for IRQ %d\n",
>>>> +			       irq_domain_get_of_node(data->domain), type,
>>>> +			       data->irq);
>>>
>>> A failing set_type already triggers a kernel message.
>>
>> I'll remove this.
>>
>>>> +			return -EBADR;
>>>
>>> That's a pretty odd error. I see it used in 3 drivers (including the
>>> one this driver replaces), but the canonical error code is -EINVAL.
>>
>> I'll change it to -EINVAL.
>>
>>>> +		}
>>>> +
>>>> +		irq_set_chip_handler_name_locked(data, chip,
>>>> +						 handle_fasteoi_irq, NULL);
>>>> +
>>>> +		writel_relaxed(nmi_src_type, base + SUN6I_NMI_CTRL);
>>>> +
>>>> +		/*
>>>> +		 * Use the trigger type from the OF node for the NMI's
>>>> +		 * R_INTC to GIC connection.
>>>> +		 */
>>>> +		type = nmi_type;
>>>
>>> This looks wrong. The GIC only supports level-high and edge-rising, so
>>> half of the possible settings will result in an error. I assume the
>>> R_INTC has an inverter controlled by nmi_src_type, and only outputs
>>> something the GIC can grok.
>>
>> nmi_type isn't the setting from the incoming IRQ. nmi_type is from
>> the interrupts property in the irqchip OF node itself. So this is a
>> fwspec for `interrupt-parent = <&gic>;`, i.e. already assumed to be
>> GIC-compatible. I'm not sure what you mean by "half of the possible
>> settings".
> 
> Ah, I see. I misread where nmi_type was coming from. Please ignore me.
> 
>>
>> Maybe I should remove the `interrupts` property and hardcode the
>> number and type connecting to the GIC? If I did that, I'm not quite
>> sure whether it would be high or rising.
> 
> I guess that the output of this block is a level signal, so you should
> probably enforce that.

Okay, I'll do that.

>> The output to the GIC is literally the bit in the pending register:
>> 1 for pending, 0 for not. Since that is after a latch (regardless of
>> the input trigger type) it sounds like it should be level-high,
>> because a pulse would have already been converted to a steady
>> signal. Or does it depend on when I clear the latch?
> 
> Level and edge will have different latch clearing requirements, as
> outlined above. For level, it needs to be cleared after handling the
> interrupt, at the point where you would deactivate it in the GIC
> (.irq_eoi). For edge, that's an Ack.
> 
> [...]
> 
>>>> +static int sun6i_r_intc_domain_alloc(struct irq_domain *domain,
>>>> +				     unsigned int virq,
>>>> +				     unsigned int nr_irqs, void *arg)
>>>> +{
>>>> +	struct irq_fwspec *fwspec = arg;
>>>> +	struct irq_fwspec gic_fwspec;
>>>> +	unsigned long hwirq;
>>>> +	unsigned int type;
>>>> +	int i, ret;
>>>> +
>>>> +	ret = sun6i_r_intc_domain_translate(domain, fwspec, &hwirq, &type);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +	if (hwirq + nr_irqs > SUN6I_NR_HWIRQS)
>>>> +		return -EINVAL;
>>>> +
>>>> +	/* Construct a GIC-compatible fwspec from this fwspec. */
>>>> +	gic_fwspec = (struct irq_fwspec) {
>>>> +		.fwnode      = domain->parent->fwnode,
>>>> +		.param_count = 3,
>>>> +		.param       = { GIC_SPI, hwirq, type },
>>>> +	};
>>>> +
>>>> +	for (i = 0; i < nr_irqs; ++i)
>>>> +		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
>>>> +					      &sun6i_r_intc_level_chip, NULL);
>>>
>>> Unconditionally level, without looking at the requested type?
>>
>> __setup_irq calls __irq_set_trigger if any trigger is provided, which calls
>> chip->irq_set_type unconditionally. So I don't think the chip here matters,
>> because .irq_set_type will be called before the IRQ is enabled anyway. Again,
>> maybe I'm missing something.
> 
> It doesn't really matter, but it is a bit odd to have the information
> at hand, and ignore it. This at least deserves a comment.
> 
>> For non-NMI IRQs, the choice of chip doesn't matter, because this
>> driver handles nothing but .irq_set_wake for them (should I provide
>> a third chip for this that doesn't provide its own
>> ack/mask/unmask?).
> 
> I think you could handle the NMI with its own single irqchip (for both
> level and edge, only checking for the configuration in ack/eoi), and
> have a non-NMI chip for the rest.

I will try that.

>>
>>>> +
>>>> +	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_fwspec);
>>>> +}
>>>> +
>>>> +static const struct irq_domain_ops sun6i_r_intc_domain_ops = {
>>>> +	.translate	= sun6i_r_intc_domain_translate,
>>>> +	.alloc		= sun6i_r_intc_domain_alloc,
>>>> +	.free		= irq_domain_free_irqs_common,
>>>> +};
>>>> +
>>>> +static void sun6i_r_intc_resume(void)
>>>> +{
>>>> +	int i;
>>>> +
>>>> +	/* Only the NMI is relevant during normal operation. */
>>>> +	writel_relaxed(SUN6I_NMI_IRQ_BIT, base + SUN6I_IRQ_ENABLE(0));
>>>> +	for (i = 1; i < BITS_TO_U32(SUN6I_NR_IRQS); ++i)
>>>> +		writel_relaxed(0, base + SUN6I_IRQ_ENABLE(i));
>>>
>>> If only the NMI is relevant, why are the other interrupts enabled?
>>> Shouldn't this be moved to the following patch (I presume this is
>>> wake-up related...).
>>
>> The other IRQs aren't enabled? I'm writing all zeroes to the enable register.
> 
> Duh. -ECANTREAD.
> 
>>>> +}
>>>> +
>>>> +static int __init sun6i_r_intc_init(struct device_node *node,
>>>> +				    struct device_node *parent)
>>>> +{
>>>> +	struct irq_domain *domain, *parent_domain;
>>>> +	struct of_phandle_args parent_irq;
>>>> +	int ret;
>>>> +
>>>> +	/* Extract the NMI's R_INTC to GIC mapping from the OF node. */
>>>> +	ret = of_irq_parse_one(node, 0, &parent_irq);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +	if (parent_irq.args_count < 3 || parent_irq.args[0] != GIC_SPI)
>>>> +		return -EINVAL;
>>>> +	nmi_hwirq = parent_irq.args[1];
>>>> +	nmi_type = parent_irq.args[2];
>>>
>>> This looks a lot like the translate callback.
>>
>> Yes, I could use that here.
>>
>>>> +
>>>> +	parent_domain = irq_find_host(parent);
>>>> +	if (!parent_domain) {
>>>> +		pr_err("%pOF: Failed to obtain parent domain\n", node);
>>>> +		return -ENXIO;
>>>> +	}
>>>> +
>>>> +	base = of_io_request_and_map(node, 0, NULL);
>>>> +	if (IS_ERR(base)) {
>>>> +		pr_err("%pOF: Failed to map MMIO region\n", node);
>>>> +		return PTR_ERR(base);
>>>> +	}
>>>> +
>>>> +	sun6i_r_intc_nmi_ack();
>>>> +	sun6i_r_intc_resume();
>>>> +
>>>> +	domain = irq_domain_add_hierarchy(parent_domain, 0,
>>>> +					  SUN6I_NR_HWIRQS, node,
>>>> +					  &sun6i_r_intc_domain_ops, NULL);
>>>> +	if (!domain) {
>>>> +		pr_err("%pOF: Failed to allocate domain\n", node);
>>>> +		iounmap(base);
>>>> +		return -ENOMEM;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +IRQCHIP_DECLARE(sun6i_r_intc, "allwinner,sun6i-a31-r-intc", sun6i_r_intc_init);
>>>
>>> Thanks,
>>>
>>> 	M.
>>>
>>
>> Thank you for your (extremely quick, I must say) review!
> 
> Locked up home until Wednesday. I try to keep myself busy...
> 
> Thanks,
> 
> 	M.
> 

Thanks,
Samuel

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 03/10] irqchip/sun6i-r: Use a stacked irqchip driver
  2021-01-04  3:46           ` Samuel Holland
@ 2021-01-04 10:03             ` Marc Zyngier
  -1 siblings, 0 replies; 44+ messages in thread
From: Marc Zyngier @ 2021-01-04 10:03 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Thomas Gleixner, Rob Herring, Maxime Ripard, Chen-Yu Tsai,
	Jernej Skrabec, Russell King, Catalin Marinas, Will Deacon,
	Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel

On 2021-01-04 03:46, Samuel Holland wrote:
> On 1/3/21 7:10 AM, Marc Zyngier wrote:
>> On Sun, 03 Jan 2021 12:08:43 +0000,
>> Samuel Holland <samuel@sholland.org> wrote:
>>> 
>>> On 1/3/21 5:27 AM, Marc Zyngier wrote:

[...]

>>> For edge interrupts, don't you want to ack as early as possible,
>>> before the handler clears the source of the interrupt? That way if a
>>> second interrupt comes in while you're handling the first one, you
>>> don't ack the second one without handling it?
>> 
>> It completely depends on what this block does. If, as I expect, it
>> latches the interrupt, then it needs clearing after the GIC has acked
>> the incoming interrupt.
> 
> Yes, there is an internal S/R latch.
>  - For edge interrupts, the latch is set once for each pulse.
>  - For level interrupts, it gets set continuously as long as the
>    pin is high/low.
>  - Writing a "1" to bit 0 of PENDING resets the latch.
>  - The output of the latch goes to the GIC.
> 
>>>> It also begs the question: why would you want to clear the signal to
>>>> the GIC on mask (or unmask)? The expectations are that a pending
>>>> interrupt is preserved across a mask/unmask sequence.
>>> 
>>> I hadn't thought about anything masking the IRQ outside of the
>>> handler; but you're right, this breaks that case. I'm trying to work
>>> within the constraints of stacking the GIC driver, which assumes
>>> handle_fasteoi_irq, so it sounds like I should switch back to
>>> handle_fasteoi_ack_irq and use .irq_ack. Or based on your previous
>>> paragraph, maybe I'm missing some other consideration?
>> 
>> handle_fasteoi_ack_irq() sounds like a good match for edge
>> interrupts. Do you actually need to do anything for level signals? If
>> you do, piggybacking on .irq_eoi would do the trick.
> 
> For level interrupts, I have to reset the latch (see above) after the 
> source of
> the interrupt is cleared.

Right, so that is definitely to be done in .irq_eoi, at least in the
non-threaded case (as it doesn't involve masking/unmasking).

> That was the bug with v2: I set IRQ_EOI_THREADED so .irq_eoi would run 
> after the
> thread. But with GICv2 EOImode==0, that blocked other interrupts from 
> being
> received during the IRQ thread. Which is why I moved it to .irq_unmask 
> and
> removed the flag: so .irq_eoi runs at the end of the hardirq 
> (unblocking further
> interrupts at the GIC), and .irq_unmask resets the latch at the end of
> the thread.
> 
> With the flag removed, but still clearing the latch in .irq_eoi, every 
> edge IRQ

edge? Didn't you mean level here? Edge interrupts really should clear
the latch in .irq_ack.

> was followed by a second, spurious IRQ after the thread finished.
> 
> Does that make sense?

It does. It is a bit of a kludge, but hey, silly HW (if only this could 
be
turned into a bypass, it'd all be simpler).

To sum it up, this is what I'd expect to see:

For edge interrupts:
- clear latch in .irq_ack and .irq_set_irqchip_state(PENDING)
- interrupt flow set to fasteoi_ack

For level interrupts
- clear latch in .irq_eoi (non-threaded) and .irq_unmask (threaded)
- interrupt flow set to fasteoi (though leaving to the _ack version
   should not hurt).

Thanks,

         M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 03/10] irqchip/sun6i-r: Use a stacked irqchip driver
@ 2021-01-04 10:03             ` Marc Zyngier
  0 siblings, 0 replies; 44+ messages in thread
From: Marc Zyngier @ 2021-01-04 10:03 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, devicetree, Jernej Skrabec, Catalin Marinas,
	Russell King, Maxime Ripard, linux-kernel, Chen-Yu Tsai,
	Rob Herring, Thomas Gleixner, Will Deacon, linux-arm-kernel

On 2021-01-04 03:46, Samuel Holland wrote:
> On 1/3/21 7:10 AM, Marc Zyngier wrote:
>> On Sun, 03 Jan 2021 12:08:43 +0000,
>> Samuel Holland <samuel@sholland.org> wrote:
>>> 
>>> On 1/3/21 5:27 AM, Marc Zyngier wrote:

[...]

>>> For edge interrupts, don't you want to ack as early as possible,
>>> before the handler clears the source of the interrupt? That way if a
>>> second interrupt comes in while you're handling the first one, you
>>> don't ack the second one without handling it?
>> 
>> It completely depends on what this block does. If, as I expect, it
>> latches the interrupt, then it needs clearing after the GIC has acked
>> the incoming interrupt.
> 
> Yes, there is an internal S/R latch.
>  - For edge interrupts, the latch is set once for each pulse.
>  - For level interrupts, it gets set continuously as long as the
>    pin is high/low.
>  - Writing a "1" to bit 0 of PENDING resets the latch.
>  - The output of the latch goes to the GIC.
> 
>>>> It also begs the question: why would you want to clear the signal to
>>>> the GIC on mask (or unmask)? The expectations are that a pending
>>>> interrupt is preserved across a mask/unmask sequence.
>>> 
>>> I hadn't thought about anything masking the IRQ outside of the
>>> handler; but you're right, this breaks that case. I'm trying to work
>>> within the constraints of stacking the GIC driver, which assumes
>>> handle_fasteoi_irq, so it sounds like I should switch back to
>>> handle_fasteoi_ack_irq and use .irq_ack. Or based on your previous
>>> paragraph, maybe I'm missing some other consideration?
>> 
>> handle_fasteoi_ack_irq() sounds like a good match for edge
>> interrupts. Do you actually need to do anything for level signals? If
>> you do, piggybacking on .irq_eoi would do the trick.
> 
> For level interrupts, I have to reset the latch (see above) after the 
> source of
> the interrupt is cleared.

Right, so that is definitely to be done in .irq_eoi, at least in the
non-threaded case (as it doesn't involve masking/unmasking).

> That was the bug with v2: I set IRQ_EOI_THREADED so .irq_eoi would run 
> after the
> thread. But with GICv2 EOImode==0, that blocked other interrupts from 
> being
> received during the IRQ thread. Which is why I moved it to .irq_unmask 
> and
> removed the flag: so .irq_eoi runs at the end of the hardirq 
> (unblocking further
> interrupts at the GIC), and .irq_unmask resets the latch at the end of
> the thread.
> 
> With the flag removed, but still clearing the latch in .irq_eoi, every 
> edge IRQ

edge? Didn't you mean level here? Edge interrupts really should clear
the latch in .irq_ack.

> was followed by a second, spurious IRQ after the thread finished.
> 
> Does that make sense?

It does. It is a bit of a kludge, but hey, silly HW (if only this could 
be
turned into a bypass, it'd all be simpler).

To sum it up, this is what I'd expect to see:

For edge interrupts:
- clear latch in .irq_ack and .irq_set_irqchip_state(PENDING)
- interrupt flow set to fasteoi_ack

For level interrupts
- clear latch in .irq_eoi (non-threaded) and .irq_unmask (threaded)
- interrupt flow set to fasteoi (though leaving to the _ack version
   should not hurt).

Thanks,

         M.
-- 
Jazz is not dead. It just smells funny...

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 01/10] dt-bindings: irq: sun6i-r: Split the binding from sun7i-nmi
  2021-01-03 10:30   ` Samuel Holland
@ 2021-01-08  9:44     ` Maxime Ripard
  -1 siblings, 0 replies; 44+ messages in thread
From: Maxime Ripard @ 2021-01-08  9:44 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Thomas Gleixner, Marc Zyngier, Rob Herring, Chen-Yu Tsai,
	Jernej Skrabec, Russell King, Catalin Marinas, Will Deacon,
	Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel,
	linux-sunxi

Hi Samuel,

Thanks a lot for working on this

I'm fine with the rest of the work, but I have a couple of questions

On Sun, Jan 03, 2021 at 04:30:52AM -0600, Samuel Holland wrote:
> The R_INTC in the A31 and newer sun8i/sun50i SoCs has additional
> functionality compared to the sun7i/sun9i NMI controller. Among other
> things, it multiplexes up to 128 interrupts corresponding to (and in
> parallel to) the first 128 GIC SPIs. This means the NMI is no longer the
> lowest-numbered interrupt, since it is SPI 32 or 96 (depending on SoC).
> 
> To allow access to all multiplexed IRQs, the R_INTC requires a new
> binding where the interrupt number matches the GIC interrupt number.
> For simplicity, copy the three-cell GIC binding; this disambiguates
> interrupt 0 in the old binding (the NMI) from interrupt 0 in the new
> binding (SPI 0) by the number of cells.

It's not really clear to me what the ambiguity is between the NMI and
the SPI 0 interrupt?

In general, it looks like switching to a 3-cell binding with the GIC SPI
value looks weird to me, since the GIC isn't the parent at all of these
interrupts.

If the ambiguity is that a stacked irqchip driver needs to have the same
interrupt number than the GIC, and that the 0 interrupt for the NMI
controller (used by the PMIC) and is actually the 32 (or 96) GIC
interrupt and thus breaks that requirement, can't we fix this in the
driver based on the compatible?

Something like if the interrupt number is 0, with a A31 or newer
compatible, then add the proper offset in sun6i_r_intc_domain_alloc?

Maxime

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 01/10] dt-bindings: irq: sun6i-r: Split the binding from sun7i-nmi
@ 2021-01-08  9:44     ` Maxime Ripard
  0 siblings, 0 replies; 44+ messages in thread
From: Maxime Ripard @ 2021-01-08  9:44 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, devicetree, Jernej Skrabec, Marc Zyngier,
	linux-sunxi, Russell King, linux-kernel, Chen-Yu Tsai,
	Rob Herring, Catalin Marinas, Thomas Gleixner, Will Deacon,
	linux-arm-kernel

Hi Samuel,

Thanks a lot for working on this

I'm fine with the rest of the work, but I have a couple of questions

On Sun, Jan 03, 2021 at 04:30:52AM -0600, Samuel Holland wrote:
> The R_INTC in the A31 and newer sun8i/sun50i SoCs has additional
> functionality compared to the sun7i/sun9i NMI controller. Among other
> things, it multiplexes up to 128 interrupts corresponding to (and in
> parallel to) the first 128 GIC SPIs. This means the NMI is no longer the
> lowest-numbered interrupt, since it is SPI 32 or 96 (depending on SoC).
> 
> To allow access to all multiplexed IRQs, the R_INTC requires a new
> binding where the interrupt number matches the GIC interrupt number.
> For simplicity, copy the three-cell GIC binding; this disambiguates
> interrupt 0 in the old binding (the NMI) from interrupt 0 in the new
> binding (SPI 0) by the number of cells.

It's not really clear to me what the ambiguity is between the NMI and
the SPI 0 interrupt?

In general, it looks like switching to a 3-cell binding with the GIC SPI
value looks weird to me, since the GIC isn't the parent at all of these
interrupts.

If the ambiguity is that a stacked irqchip driver needs to have the same
interrupt number than the GIC, and that the 0 interrupt for the NMI
controller (used by the PMIC) and is actually the 32 (or 96) GIC
interrupt and thus breaks that requirement, can't we fix this in the
driver based on the compatible?

Something like if the interrupt number is 0, with a A31 or newer
compatible, then add the proper offset in sun6i_r_intc_domain_alloc?

Maxime

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 01/10] dt-bindings: irq: sun6i-r: Split the binding from sun7i-nmi
  2021-01-08  9:44     ` Maxime Ripard
@ 2021-01-08 15:40       ` Samuel Holland
  -1 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-08 15:40 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Thomas Gleixner, Marc Zyngier, Rob Herring, Chen-Yu Tsai,
	Jernej Skrabec, Russell King, Catalin Marinas, Will Deacon,
	Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel,
	linux-sunxi

On 1/8/21 3:44 AM, Maxime Ripard wrote:
> Hi Samuel,
> 
> Thanks a lot for working on this
> 
> I'm fine with the rest of the work, but I have a couple of questions
> 
> On Sun, Jan 03, 2021 at 04:30:52AM -0600, Samuel Holland wrote:
>> The R_INTC in the A31 and newer sun8i/sun50i SoCs has additional
>> functionality compared to the sun7i/sun9i NMI controller. Among other
>> things, it multiplexes up to 128 interrupts corresponding to (and in
>> parallel to) the first 128 GIC SPIs. This means the NMI is no longer the
>> lowest-numbered interrupt, since it is SPI 32 or 96 (depending on SoC).
>>
>> To allow access to all multiplexed IRQs, the R_INTC requires a new
>> binding where the interrupt number matches the GIC interrupt number.
>> For simplicity, copy the three-cell GIC binding; this disambiguates
>> interrupt 0 in the old binding (the NMI) from interrupt 0 in the new
>> binding (SPI 0) by the number of cells.
> 
> It's not really clear to me what the ambiguity is between the NMI and
> the SPI 0 interrupt?

Here's the ASCII art I will include in v4:

            NMI IRQ               DIRECT IRQs          MUXED IRQs
             bit 0                 bits 1-18           bits 19-31

  +---------+                     +---------+   +---------+  +---------+
  | NMI Pad |                     |  IRQ d  |   |  IRQ m  |  | IRQ m+7 |
  +---------+                     +---------+   +---------+  +---------+
       |                            |     |        |    |      |    |
       |                            |     |        |    |......|    |
+------V------+ +-------------+     |     |        | +--V------V--+ |
|   Invert/   | |    Write    |     |     |        | |  AND with  | |
| Edge Detect | |  PENDING[0] |     |     |        | |  MUX[m/8]  | |
+-------------+ +-------------+     |     |        | +------------+ |
           |       |                |     |        |       |        |
        +--V-------V--+          +--V--+  |     +--V--+    |     +--V--+
        | Set    Reset|          | GIC |  |     | GIC |    |     | GIC |
        |    Latch    |          | SPI |  |     | SPI |... |  ...| SPI |
        +-------------+          | N+d |  |     |  m  |    |     | m+7 |
            |     |              +-----+  |     +-----+    |     +-----+
            |     |                       |                |
    +-------V-+ +-V-----------+ +---------V---+  +---------V----------+
    | GIC SPI | |   AND with  | |   AND with  |  |      AND with      |
    | N (=32) | |  ENABLE[0]  | |  ENABLE[d]  |  |   ENABLE[19+m/8]   |
    +---------+ +-------------+ +-------------+  +--------------------+
                       |               |                   |
                +------V------+ +------V------+  +---------V----------+
                |    Read     | |    Read     |  |       Read         |
                |  PENDING[0] | |  PENDING[d] |  |   PENDING[19+m/8]  |
                +-------------+ +-------------+  +--------------------+

There are two overlapping ranges of IRQs supported by the controller,
and so there are two different IRQs you could call "IRQ 0":
  - Bit 0 of PENDING/ENABLE/MASK, aka d==0, the NMI
    - This maps to bit 32 of the MUX register range (SPI 32)
    - This is what the old binding calls "IRQ 0"
  - Bit 0 of MUX, aka m==0, aka SPI 0, the UART0 IRQ
    - This maps to bit 19 of PENDING/ENABLE/MASK
    - This is what the new binding calls "IRQ 0"

You can see this insertion in the middle of the MUX range when looking
at the mask of implemented MUX bits in the A31 variant:
  0xffffffff,
  0xfff80000, <<< this gap here is for the 19 direct IRQs
  0xffffffff,
  0x0000000f,

If you call the NMI "IRQ 0", then there is no way to specify the muxed
IRQs. SPI 0 maps to bit 19, but so do SPI 1-7. So if I was to specify
"IRQ 19", you wouldn't know which of those 8 muxed SPIs I am referring to.

On the other hand, if you call the first muxed IRQ "IRQ 0", then there
is an unambiguous number for every interrupt supported by this driver.

> In general, it looks like switching to a 3-cell binding with the GIC SPI
> value looks weird to me, since the GIC isn't the parent at all of these
> interrupts.

The GIC is *a* parent of all of these interrupts, and is *the* parent of
the NMI.

> If the ambiguity is that a stacked irqchip driver needs to have the same
> interrupt number than the GIC, and that the 0 interrupt for the NMI
> controller (used by the PMIC) and is actually the 32 (or 96) GIC
> interrupt and thus breaks that requirement, can't we fix this in the
> driver based on the compatible?

No, while the NMI is direct "IRQ 0" at this irqchip, it is *also* muxed
"IRQ 32" at this same irqchip.

> Something like if the interrupt number is 0, with a A31 or newer
> compatible, then add the proper offset in sun6i_r_intc_domain_alloc?

If you translate 0 to 32, then you cannot represent muxed IRQ 0 (the
UART0 IRQ) at all.

> Maxime

Cheers,
Samuel


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 01/10] dt-bindings: irq: sun6i-r: Split the binding from sun7i-nmi
@ 2021-01-08 15:40       ` Samuel Holland
  0 siblings, 0 replies; 44+ messages in thread
From: Samuel Holland @ 2021-01-08 15:40 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ondrej Jirman, devicetree, Jernej Skrabec, Marc Zyngier,
	linux-sunxi, Russell King, linux-kernel, Chen-Yu Tsai,
	Rob Herring, Catalin Marinas, Thomas Gleixner, Will Deacon,
	linux-arm-kernel

On 1/8/21 3:44 AM, Maxime Ripard wrote:
> Hi Samuel,
> 
> Thanks a lot for working on this
> 
> I'm fine with the rest of the work, but I have a couple of questions
> 
> On Sun, Jan 03, 2021 at 04:30:52AM -0600, Samuel Holland wrote:
>> The R_INTC in the A31 and newer sun8i/sun50i SoCs has additional
>> functionality compared to the sun7i/sun9i NMI controller. Among other
>> things, it multiplexes up to 128 interrupts corresponding to (and in
>> parallel to) the first 128 GIC SPIs. This means the NMI is no longer the
>> lowest-numbered interrupt, since it is SPI 32 or 96 (depending on SoC).
>>
>> To allow access to all multiplexed IRQs, the R_INTC requires a new
>> binding where the interrupt number matches the GIC interrupt number.
>> For simplicity, copy the three-cell GIC binding; this disambiguates
>> interrupt 0 in the old binding (the NMI) from interrupt 0 in the new
>> binding (SPI 0) by the number of cells.
> 
> It's not really clear to me what the ambiguity is between the NMI and
> the SPI 0 interrupt?

Here's the ASCII art I will include in v4:

            NMI IRQ               DIRECT IRQs          MUXED IRQs
             bit 0                 bits 1-18           bits 19-31

  +---------+                     +---------+   +---------+  +---------+
  | NMI Pad |                     |  IRQ d  |   |  IRQ m  |  | IRQ m+7 |
  +---------+                     +---------+   +---------+  +---------+
       |                            |     |        |    |      |    |
       |                            |     |        |    |......|    |
+------V------+ +-------------+     |     |        | +--V------V--+ |
|   Invert/   | |    Write    |     |     |        | |  AND with  | |
| Edge Detect | |  PENDING[0] |     |     |        | |  MUX[m/8]  | |
+-------------+ +-------------+     |     |        | +------------+ |
           |       |                |     |        |       |        |
        +--V-------V--+          +--V--+  |     +--V--+    |     +--V--+
        | Set    Reset|          | GIC |  |     | GIC |    |     | GIC |
        |    Latch    |          | SPI |  |     | SPI |... |  ...| SPI |
        +-------------+          | N+d |  |     |  m  |    |     | m+7 |
            |     |              +-----+  |     +-----+    |     +-----+
            |     |                       |                |
    +-------V-+ +-V-----------+ +---------V---+  +---------V----------+
    | GIC SPI | |   AND with  | |   AND with  |  |      AND with      |
    | N (=32) | |  ENABLE[0]  | |  ENABLE[d]  |  |   ENABLE[19+m/8]   |
    +---------+ +-------------+ +-------------+  +--------------------+
                       |               |                   |
                +------V------+ +------V------+  +---------V----------+
                |    Read     | |    Read     |  |       Read         |
                |  PENDING[0] | |  PENDING[d] |  |   PENDING[19+m/8]  |
                +-------------+ +-------------+  +--------------------+

There are two overlapping ranges of IRQs supported by the controller,
and so there are two different IRQs you could call "IRQ 0":
  - Bit 0 of PENDING/ENABLE/MASK, aka d==0, the NMI
    - This maps to bit 32 of the MUX register range (SPI 32)
    - This is what the old binding calls "IRQ 0"
  - Bit 0 of MUX, aka m==0, aka SPI 0, the UART0 IRQ
    - This maps to bit 19 of PENDING/ENABLE/MASK
    - This is what the new binding calls "IRQ 0"

You can see this insertion in the middle of the MUX range when looking
at the mask of implemented MUX bits in the A31 variant:
  0xffffffff,
  0xfff80000, <<< this gap here is for the 19 direct IRQs
  0xffffffff,
  0x0000000f,

If you call the NMI "IRQ 0", then there is no way to specify the muxed
IRQs. SPI 0 maps to bit 19, but so do SPI 1-7. So if I was to specify
"IRQ 19", you wouldn't know which of those 8 muxed SPIs I am referring to.

On the other hand, if you call the first muxed IRQ "IRQ 0", then there
is an unambiguous number for every interrupt supported by this driver.

> In general, it looks like switching to a 3-cell binding with the GIC SPI
> value looks weird to me, since the GIC isn't the parent at all of these
> interrupts.

The GIC is *a* parent of all of these interrupts, and is *the* parent of
the NMI.

> If the ambiguity is that a stacked irqchip driver needs to have the same
> interrupt number than the GIC, and that the 0 interrupt for the NMI
> controller (used by the PMIC) and is actually the 32 (or 96) GIC
> interrupt and thus breaks that requirement, can't we fix this in the
> driver based on the compatible?

No, while the NMI is direct "IRQ 0" at this irqchip, it is *also* muxed
"IRQ 32" at this same irqchip.

> Something like if the interrupt number is 0, with a A31 or newer
> compatible, then add the proper offset in sun6i_r_intc_domain_alloc?

If you translate 0 to 32, then you cannot represent muxed IRQ 0 (the
UART0 IRQ) at all.

> Maxime

Cheers,
Samuel


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 01/10] dt-bindings: irq: sun6i-r: Split the binding from sun7i-nmi
  2021-01-03 10:30   ` Samuel Holland
@ 2021-01-11 22:29     ` Rob Herring
  -1 siblings, 0 replies; 44+ messages in thread
From: Rob Herring @ 2021-01-11 22:29 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Thomas Gleixner, Marc Zyngier, Maxime Ripard, Chen-Yu Tsai,
	Jernej Skrabec, Russell King, Catalin Marinas, Will Deacon,
	Ondrej Jirman, devicetree, linux-arm-kernel, linux-kernel,
	linux-sunxi

On Sun, Jan 03, 2021 at 04:30:52AM -0600, Samuel Holland wrote:
> The R_INTC in the A31 and newer sun8i/sun50i SoCs has additional
> functionality compared to the sun7i/sun9i NMI controller. Among other
> things, it multiplexes up to 128 interrupts corresponding to (and in
> parallel to) the first 128 GIC SPIs. This means the NMI is no longer the
> lowest-numbered interrupt, since it is SPI 32 or 96 (depending on SoC).
> 
> To allow access to all multiplexed IRQs, the R_INTC requires a new
> binding where the interrupt number matches the GIC interrupt number.
> For simplicity, copy the three-cell GIC binding; this disambiguates
> interrupt 0 in the old binding (the NMI) from interrupt 0 in the new
> binding (SPI 0) by the number of cells.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  .../allwinner,sun6i-a31-r-intc.yaml           | 64 +++++++++++++++++++
>  .../allwinner,sun7i-a20-sc-nmi.yaml           | 10 ---
>  2 files changed, 64 insertions(+), 10 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml
> 
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml
> new file mode 100644
> index 000000000000..18805b6555c2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml
> @@ -0,0 +1,64 @@
> +# SPDX-License-Identifier: GPL-2.0
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Allwinner A31 NMI/Wakeup Interrupt Controller Device Tree Bindings
> +
> +maintainers:
> +  - Chen-Yu Tsai <wens@csie.org>
> +  - Maxime Ripard <mripard@kernel.org>
> +
> +allOf:
> +  - $ref: /schemas/interrupt-controller.yaml#
> +
> +properties:
> +  "#interrupt-cells":
> +    const: 3
> +    description:
> +      The first cell is GIC_SPI (0), the second cell is the IRQ number, and
> +      the third cell is the trigger type as defined in interrupt.txt in this
> +      directory.
> +
> +  compatible:
> +    oneOf:
> +      - items:
> +          - enum:
> +              - allwinner,sun8i-a83t-r-intc
> +              - allwinner,sun50i-a64-r-intc
> +              - allwinner,sun50i-h6-r-intc
> +          - const: allwinner,sun6i-a31-r-intc
> +      - const: allwinner,sun6i-a31-r-intc
> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  interrupt-controller: true
> +
> +required:
> +  - "#interrupt-cells"
> +  - compatible
> +  - reg
> +  - interrupts
> +  - interrupt-controller
> +
> +unevaluatedProperties: false

additionalProperties: false

(a bit stricter and actually implemented ATM)

> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +    r_intc: interrupt-controller@1f00c00 {
> +            compatible = "allwinner,sun50i-a64-r-intc",
> +                         "allwinner,sun6i-a31-r-intc";
> +            interrupt-controller;
> +            #interrupt-cells = <3>;
> +            reg = <0x01f00c00 0x400>;
> +            interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
> +    };
> +
> +...
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml
> index 8acca0ae3129..f34ecc8c7093 100644
> --- a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml
> +++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml
> @@ -22,23 +22,13 @@ properties:
>  
>    compatible:
>      oneOf:
> -      - const: allwinner,sun6i-a31-r-intc
>        - const: allwinner,sun6i-a31-sc-nmi
>          deprecated: true
>        - const: allwinner,sun7i-a20-sc-nmi
> -      - items:
> -          - const: allwinner,sun8i-a83t-r-intc
> -          - const: allwinner,sun6i-a31-r-intc
>        - const: allwinner,sun9i-a80-nmi
> -      - items:
> -          - const: allwinner,sun50i-a64-r-intc
> -          - const: allwinner,sun6i-a31-r-intc
>        - items:
>            - const: allwinner,sun50i-a100-nmi
>            - const: allwinner,sun9i-a80-nmi
> -      - items:
> -          - const: allwinner,sun50i-h6-r-intc
> -          - const: allwinner,sun6i-a31-r-intc
>  
>    reg:
>      maxItems: 1
> -- 
> 2.26.2
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 01/10] dt-bindings: irq: sun6i-r: Split the binding from sun7i-nmi
@ 2021-01-11 22:29     ` Rob Herring
  0 siblings, 0 replies; 44+ messages in thread
From: Rob Herring @ 2021-01-11 22:29 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, devicetree, Jernej Skrabec, Marc Zyngier,
	linux-sunxi, Russell King, Maxime Ripard, linux-kernel,
	Chen-Yu Tsai, Catalin Marinas, Thomas Gleixner, Will Deacon,
	linux-arm-kernel

On Sun, Jan 03, 2021 at 04:30:52AM -0600, Samuel Holland wrote:
> The R_INTC in the A31 and newer sun8i/sun50i SoCs has additional
> functionality compared to the sun7i/sun9i NMI controller. Among other
> things, it multiplexes up to 128 interrupts corresponding to (and in
> parallel to) the first 128 GIC SPIs. This means the NMI is no longer the
> lowest-numbered interrupt, since it is SPI 32 or 96 (depending on SoC).
> 
> To allow access to all multiplexed IRQs, the R_INTC requires a new
> binding where the interrupt number matches the GIC interrupt number.
> For simplicity, copy the three-cell GIC binding; this disambiguates
> interrupt 0 in the old binding (the NMI) from interrupt 0 in the new
> binding (SPI 0) by the number of cells.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  .../allwinner,sun6i-a31-r-intc.yaml           | 64 +++++++++++++++++++
>  .../allwinner,sun7i-a20-sc-nmi.yaml           | 10 ---
>  2 files changed, 64 insertions(+), 10 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml
> 
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml
> new file mode 100644
> index 000000000000..18805b6555c2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml
> @@ -0,0 +1,64 @@
> +# SPDX-License-Identifier: GPL-2.0
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/interrupt-controller/allwinner,sun6i-a31-r-intc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Allwinner A31 NMI/Wakeup Interrupt Controller Device Tree Bindings
> +
> +maintainers:
> +  - Chen-Yu Tsai <wens@csie.org>
> +  - Maxime Ripard <mripard@kernel.org>
> +
> +allOf:
> +  - $ref: /schemas/interrupt-controller.yaml#
> +
> +properties:
> +  "#interrupt-cells":
> +    const: 3
> +    description:
> +      The first cell is GIC_SPI (0), the second cell is the IRQ number, and
> +      the third cell is the trigger type as defined in interrupt.txt in this
> +      directory.
> +
> +  compatible:
> +    oneOf:
> +      - items:
> +          - enum:
> +              - allwinner,sun8i-a83t-r-intc
> +              - allwinner,sun50i-a64-r-intc
> +              - allwinner,sun50i-h6-r-intc
> +          - const: allwinner,sun6i-a31-r-intc
> +      - const: allwinner,sun6i-a31-r-intc
> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  interrupt-controller: true
> +
> +required:
> +  - "#interrupt-cells"
> +  - compatible
> +  - reg
> +  - interrupts
> +  - interrupt-controller
> +
> +unevaluatedProperties: false

additionalProperties: false

(a bit stricter and actually implemented ATM)

> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +    r_intc: interrupt-controller@1f00c00 {
> +            compatible = "allwinner,sun50i-a64-r-intc",
> +                         "allwinner,sun6i-a31-r-intc";
> +            interrupt-controller;
> +            #interrupt-cells = <3>;
> +            reg = <0x01f00c00 0x400>;
> +            interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
> +    };
> +
> +...
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml
> index 8acca0ae3129..f34ecc8c7093 100644
> --- a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml
> +++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml
> @@ -22,23 +22,13 @@ properties:
>  
>    compatible:
>      oneOf:
> -      - const: allwinner,sun6i-a31-r-intc
>        - const: allwinner,sun6i-a31-sc-nmi
>          deprecated: true
>        - const: allwinner,sun7i-a20-sc-nmi
> -      - items:
> -          - const: allwinner,sun8i-a83t-r-intc
> -          - const: allwinner,sun6i-a31-r-intc
>        - const: allwinner,sun9i-a80-nmi
> -      - items:
> -          - const: allwinner,sun50i-a64-r-intc
> -          - const: allwinner,sun6i-a31-r-intc
>        - items:
>            - const: allwinner,sun50i-a100-nmi
>            - const: allwinner,sun9i-a80-nmi
> -      - items:
> -          - const: allwinner,sun50i-h6-r-intc
> -          - const: allwinner,sun6i-a31-r-intc
>  
>    reg:
>      maxItems: 1
> -- 
> 2.26.2
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 02/10] dt-bindings: irq: sun6i-r: Add a compatible for the H3
  2021-01-03 10:30   ` Samuel Holland
@ 2021-01-11 22:29     ` Rob Herring
  -1 siblings, 0 replies; 44+ messages in thread
From: Rob Herring @ 2021-01-11 22:29 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Maxime Ripard, Rob Herring, linux-sunxi, Catalin Marinas,
	Ondrej Jirman, Thomas Gleixner, linux-kernel, Chen-Yu Tsai,
	linux-arm-kernel, Marc Zyngier, devicetree, Jernej Skrabec,
	Will Deacon, Russell King

On Sun, 03 Jan 2021 04:30:53 -0600, Samuel Holland wrote:
> The Allwinner H3 SoC contains an R_INTC that is, as far as we know,
> compatible with the R_INTC present in other sun8i/sun50i SoCs starting
> with the A31. Since the R_INTC hardware is undocumented, introduce a new
> compatible for the R_INTC variant in this SoC, in case there turns out
> to be some difference.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  .../interrupt-controller/allwinner,sun6i-a31-r-intc.yaml         | 1 +
>  1 file changed, 1 insertion(+)
> 

Acked-by: Rob Herring <robh@kernel.org>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 02/10] dt-bindings: irq: sun6i-r: Add a compatible for the H3
@ 2021-01-11 22:29     ` Rob Herring
  0 siblings, 0 replies; 44+ messages in thread
From: Rob Herring @ 2021-01-11 22:29 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Ondrej Jirman, devicetree, Jernej Skrabec, Catalin Marinas,
	linux-kernel, Maxime Ripard, Russell King, linux-sunxi,
	Rob Herring, Marc Zyngier, Thomas Gleixner, Chen-Yu Tsai,
	Will Deacon, linux-arm-kernel

On Sun, 03 Jan 2021 04:30:53 -0600, Samuel Holland wrote:
> The Allwinner H3 SoC contains an R_INTC that is, as far as we know,
> compatible with the R_INTC present in other sun8i/sun50i SoCs starting
> with the A31. Since the R_INTC hardware is undocumented, introduce a new
> compatible for the R_INTC variant in this SoC, in case there turns out
> to be some difference.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  .../interrupt-controller/allwinner,sun6i-a31-r-intc.yaml         | 1 +
>  1 file changed, 1 insertion(+)
> 

Acked-by: Rob Herring <robh@kernel.org>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 44+ messages in thread

end of thread, other threads:[~2021-01-11 22:31 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-03 10:30 [PATCH v3 00/10] sunxi: Support IRQ wakeup from deep sleep Samuel Holland
2021-01-03 10:30 ` Samuel Holland
2021-01-03 10:30 ` [PATCH v3 01/10] dt-bindings: irq: sun6i-r: Split the binding from sun7i-nmi Samuel Holland
2021-01-03 10:30   ` Samuel Holland
2021-01-08  9:44   ` Maxime Ripard
2021-01-08  9:44     ` Maxime Ripard
2021-01-08 15:40     ` Samuel Holland
2021-01-08 15:40       ` Samuel Holland
2021-01-11 22:29   ` Rob Herring
2021-01-11 22:29     ` Rob Herring
2021-01-03 10:30 ` [PATCH v3 02/10] dt-bindings: irq: sun6i-r: Add a compatible for the H3 Samuel Holland
2021-01-03 10:30   ` Samuel Holland
2021-01-11 22:29   ` Rob Herring
2021-01-11 22:29     ` Rob Herring
2021-01-03 10:30 ` [PATCH v3 03/10] irqchip/sun6i-r: Use a stacked irqchip driver Samuel Holland
2021-01-03 10:30   ` Samuel Holland
2021-01-03 11:27   ` Marc Zyngier
2021-01-03 11:27     ` Marc Zyngier
2021-01-03 12:08     ` Samuel Holland
2021-01-03 12:08       ` Samuel Holland
2021-01-03 13:10       ` Marc Zyngier
2021-01-03 13:10         ` Marc Zyngier
2021-01-04  3:46         ` Samuel Holland
2021-01-04  3:46           ` Samuel Holland
2021-01-04 10:03           ` Marc Zyngier
2021-01-04 10:03             ` Marc Zyngier
2021-01-03 10:30 ` [PATCH v3 04/10] irqchip/sun6i-r: Add wakeup support Samuel Holland
2021-01-03 10:30   ` Samuel Holland
2021-01-03 10:30 ` [PATCH v3 05/10] ARM: dts: sunxi: Rename nmi_intc to r_intc Samuel Holland
2021-01-03 10:30   ` Samuel Holland
2021-01-03 10:30 ` [PATCH v3 06/10] ARM: dts: sunxi: Use the new r_intc binding Samuel Holland
2021-01-03 10:30   ` Samuel Holland
2021-01-03 10:30 ` [PATCH v3 07/10] ARM: dts: sunxi: h3/h5: Add r_intc node Samuel Holland
2021-01-03 10:30   ` Samuel Holland
2021-01-03 10:30 ` [PATCH v3 08/10] ARM: dts: sunxi: Move wakeup-capable IRQs to r_intc Samuel Holland
2021-01-03 10:30   ` Samuel Holland
2021-01-03 10:31 ` [PATCH v3 09/10] arm64: dts: allwinner: Use the new r_intc binding Samuel Holland
2021-01-03 10:31   ` Samuel Holland
2021-01-03 10:31 ` [PATCH v3 10/10] arm64: dts: allwinner: Move wakeup-capable IRQs to r_intc Samuel Holland
2021-01-03 10:31   ` Samuel Holland
2021-01-03 12:16 ` [PATCH v3 00/10] sunxi: Support IRQ wakeup from deep sleep Marc Zyngier
2021-01-03 12:16   ` Marc Zyngier
2021-01-03 12:43   ` Samuel Holland
2021-01-03 12:43     ` Samuel Holland

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.