* [PATCH v2 0/5] AST2700-A2 interrupt controller hierarchy and route support
@ 2026-03-06 8:07 Ryan Chen
2026-03-06 8:07 ` [PATCH v2 1/5] dt-bindings: interrupt-controller: aspeed: Add AST2700-A2 support Ryan Chen
` (4 more replies)
0 siblings, 5 replies; 9+ messages in thread
From: Ryan Chen @ 2026-03-06 8:07 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Joel Stanley,
Andrew Jeffery, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Thomas Gleixner, Thomas Gleixner
Cc: linux-kernel, devicetree, linux-arm-kernel, linux-aspeed,
linux-riscv, Ryan Chen
The AST2700 SoC has undergone multiple silicon revisions (A0, A1, A2)
prior to mass production.
A0 laid the ground-work with a split controller design (INTC0 and
INTC1) used for early development and bring-up. The interrupt
architecture was substantially reworked in the A1 to introduce an
explicit routing model and clearer hierarchy, though the split
controllers remained. The A1 interrupt architecture is unchanged in A2.
A2 is the production design. A0 and A1 are pre-production silicon and
are no longer intended for deployment outside of ASPEED.
The existing binding and driver were written against A0 prior to the A1
rework. The A0 design directly wired INTC1 instances to INTC0, and
INTC0 to the GIC of the Primary Service Processor (PSP, a Cortex-A35).
The A0 binding and driver therefore do not account for the alternative
destinations of the Secondary and Tertiary Service Processors (SSP,
TSP) and BootMCU, or the necessary route selection logic present in the
production design.
With the above context, this series replaces the existing binding and
driver.
It is not necessary for projects to maintain support for A0 due to its
pre-production nature, and between Linux, U-Boot and Zephyr there are
no upstream devicetree users of the current binding.
The new binding uses localised interrupt numbers and models the
hardware connectivity between interrupt controllers using the
aspeed,interrupt-ranges property. It is introduced in a new file before
the existing binding is removed in order to keep the diff readable.
The INTC0 driver creates a hierarchical irqdomain under the selected
upstream interrupt controller and implements route resolution logic.
INTC1 driver instances defer route selection to INTC0 and expose a
linear interrupt namespace to their parent.
A brief history of related submissions
--------------------------------------
Some modifications to the existing binding were sent to the lists in
the past. Due to process choices the revisions were difficult to track.
They are listed below.
The approaches took several forms but ended in the minor adjustment in
v6 being applied. This enabled use of the A1 design but requires
assumptions about platform route configuration defined in firmware.
These assumptions are removed by this current series.
* [PATCH] dt-bindings: interrupt-controller: aspeed: Refine AST2700 binding description and example
https://lore.kernel.org/all/20250714071753.2653620-1-ryan_chen@aspeedtech.com/
* [PATCH v2] dt-bindings: interrupt-controller: aspeed: Add parent node compatibles and refine documentation
https://lore.kernel.org/all/20250715024258.2304665-1-ryan_chen@aspeedtech.com/
* [PATCH v3 0/2] irqchip: aspeed: Add AST2700 INTC debugfs support and yaml update
https://lore.kernel.org/all/20250722095156.1672873-1-ryan_chen@aspeedtech.com/
* [PATCH v4 0/2] irqchip/ast2700-intc: Add AST2700 INTC debugfs support and yaml update
https://lore.kernel.org/all/20250812100830.145578-1-ryan_chen@aspeedtech.com/
* [PATCH v5 0/3] AST2700 interrupt controller hierarchy support
https://lore.kernel.org/all/20251022065507.1152071-1-ryan_chen@aspeedtech.com/
* [PATCH v6 0/1] Update correct AST2700 interrupt controller binding
https://lore.kernel.org/all/20251030060155.2342604-1-ryan_chen@aspeedtech.com/
Signed-off-by: Ryan Chen <ryan_chen@aspeedtech.com>
---
Changes in v2:
- Change suject to "AST2700-A2 interrupt controller hierarchy and route
support".
- Describe timeline for (pre-)production design evolution and
binding development to support the break in compatibility.
- fix "make dt_binding_check" compatible string consistance with
example.
- Split KUnit coverage out of the main driver patch.
- Link to v1: https://lore.kernel.org/r/20260205-irqchip-v1-0-b0310e06c087@aspeedtech.com
---
Ryan Chen (5):
dt-bindings: interrupt-controller: aspeed: Add AST2700-A2 support
irqchip/ast2700-intc: Add AST2700-A2 support
irqchip/ast2700-intc: Add KUnit tests for route resolution
irqchip/aspeed-intc: Remove AST2700-A0 support
dt-bindings: interrupt-controller: aspeed: Remove AST2700-A0 support
.../interrupt-controller/aspeed,ast2700-intc.yaml | 90 ----
.../aspeed,ast2700-interrupt.yaml | 189 +++++++
drivers/irqchip/.kunitconfig | 5 +
drivers/irqchip/Kconfig | 23 +
drivers/irqchip/Makefile | 3 +-
drivers/irqchip/irq-aspeed-intc.c | 139 -----
drivers/irqchip/irq-ast2700-intc0-test.c | 473 +++++++++++++++++
drivers/irqchip/irq-ast2700-intc0.c | 584 +++++++++++++++++++++
drivers/irqchip/irq-ast2700-intc1.c | 282 ++++++++++
drivers/irqchip/irq-ast2700.c | 106 ++++
drivers/irqchip/irq-ast2700.h | 47 ++
11 files changed, 1711 insertions(+), 230 deletions(-)
---
base-commit: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
change-id: 20260205-irqchip-7eaef3674de9
Best regards,
--
Ryan Chen <ryan_chen@aspeedtech.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 1/5] dt-bindings: interrupt-controller: aspeed: Add AST2700-A2 support
2026-03-06 8:07 [PATCH v2 0/5] AST2700-A2 interrupt controller hierarchy and route support Ryan Chen
@ 2026-03-06 8:07 ` Ryan Chen
2026-03-20 8:24 ` Thomas Gleixner
2026-03-23 19:07 ` Rob Herring
2026-03-06 8:07 ` [PATCH v2 2/5] irqchip/ast2700-intc: " Ryan Chen
` (3 subsequent siblings)
4 siblings, 2 replies; 9+ messages in thread
From: Ryan Chen @ 2026-03-06 8:07 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Joel Stanley,
Andrew Jeffery, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Thomas Gleixner, Thomas Gleixner
Cc: linux-kernel, devicetree, linux-arm-kernel, linux-aspeed,
linux-riscv, Ryan Chen
Introduce a new binding describing the AST2700 interrupt controller
architecture implemented in the A2 production silicon.
The AST2700 SoC has undergone multiple silicon revisions (A0, A1, A2)
prior to mass production. The interrupt architecture was substantially
reworked after the A0 revision for A1, and the A1 design is retained
unchanged in the A2 production silicon.
The existing AST2700 interrupt controller binding was written against
the pre-production A0 design. That binding does not accurately describe
the interrupt hierarchy and routing model present in A1/A2, where
interrupts can be routed to multiple processor-local interrupt
controllers (Primary Service Processor (PSP) GIC, Secondary Service
Processor (SSP)/Tertiary Service Processor (TSP) NVICs, and BootMCU
APLIC) depending on the execution context.
Hardware connectivity between interrupt controllers is expressed using
the aspeed,interrupt-ranges property.
Signed-off-by: Ryan Chen <ryan_chen@aspeedtech.com>
---
Changes in v2:
- Describe AST2700 A0/A1/A2 design evolution.
- Drop the redundant '-ic' suffix from compatible strings.
- Expand commit message to match the series cover letter context.
- fix ascii diagram
- remove intc0 label
- remove spaces before >
- drop intc1 example
---
.../aspeed,ast2700-interrupt.yaml | 189 +++++++++++++++++++++
1 file changed, 189 insertions(+)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2700-interrupt.yaml b/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2700-interrupt.yaml
new file mode 100644
index 000000000000..13398ff8be12
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2700-interrupt.yaml
@@ -0,0 +1,189 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/aspeed,ast2700-interrupt.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ASPEED AST2700 Interrupt Controllers (INTC0/INTC1)
+
+description: |
+ The ASPEED AST2700 SoC integrates two interrupt controller designs:
+
+ - INTC0: Primary controller that routes interrupt sources to upstream,
+ processor-specific interrupt controllers
+
+ - INTC1: Secondary controller whose interrupt outputs feed into
+ INTC0
+
+ The SoC contains four processors to which interrupts can be routed:
+
+ - PSP: Primary Service Processor (Cortex-A35)
+ - SSP: Secondary Service Processor (Cortex-M4)
+ - TSP: Tertiary Sevice Processor (Cortex-M4)
+ - BMCU: Boot MCU (a RISC-V microcontroller)
+
+ The following diagram illustrates the overall architecture of the
+ ASPEED AST2700 interrupt controllers:
+
+ +-----------+ +-----------+
+ | INTC0 | | INTC1(0) |
+ +-----------+ +-----------+
+ | Router | +-----------+ | Router |
+ | out int | +Peripheral + | out int |
+ +-----------+ | 0 0 <-+Controllers+ | INTM | +-----------+
+ |PSP GIC <-|---+ . . | +-----------+ | . . <-+Peripheral +
+ +-----------+ | . . | | . . | +Controllers+
+ +-----------+ | . . | | . . | +-----------+
+ |SSP NVIC <-|---+ . . <----------------+ . . |
+ +-----------+ | . . | | . . |
+ +-----------+ | . . <-------- | . . |
+ |TSP NVIC <-|---+ . . | | ----+ . . |
+ +-----------+ | . . | | | | O P |
+ | . . | | | +-----------+
+ | . . <---- | --------------------
+ | . . | | | +-----------+ |
+ | M N | | ---------+ INTC1(1) | |
+ +-----------+ | +-----------+ |
+ | . |
+ | +-----------+ |
+ -------------+ INTC1(N) | |
+ +-----------+ |
+ +--------------+ |
+ + BMCU APLIC <-+---------------------------------------------
+ +--------------+
+
+ INTC0 supports:
+ - 128 local peripheral interrupt inputs
+ - Fan-in from up to three INTC1 instances via banked interrupt lines (INTM)
+ - Local peripheral interrupt outputs
+ - Merged interrupt outputs
+ - Software interrupt outputs (SWINT)
+ - Configurable interrupt routes targeting the PSP, SSP, and TSP
+
+ INTC1 supports:
+ - 192 local peripheral interrupt inputs
+ - Banked interrupt outputs (INTM, 5 x 6 banks x 32 interrupts per bank)
+ - Configurable interrupt routes targeting the PSP, SSP, TSP, and BMCU
+
+ One INTC1 instance is always present, on the SoC's IO die. A further two
+ instances may be attached to the SoC's one INTC0 instance via LTPI (LVDS
+ Tunneling Protocol & Interface).
+
+ Interrupt numbering model
+ -------------------------
+ The binding uses a controller-local numbering model. Peripheral device
+ nodes use the INTCx local interrupt number (hwirq) in their 'interrupts' or
+ 'interrupts-extended' properties.
+
+ For AST2700, INTC0 exposes the following (inclusive) input ranges:
+
+ - 000..479: Independent interrupts
+ - 480..489: INTM0-INTM9
+ - 490..499: INTM10-INTM19
+ - 500..509: INTM20-INTM29
+ - 510..519: INTM30-INTM39
+ - 520..529: INTM40-INTM49
+
+ INTC0's (inclusive) output ranges are as follows:
+
+ - 000..127: 1:1 local peripheral interrupt output to PSP
+ - 144..151: Software interrupts from the SSP output to PSP
+ - 152..159: Software interrupts from the TSP output to PSP
+ - 192..201: INTM0-INTM9 banked outputs to PSP
+ - 208..217: INTM30-INTM39 banked outputs to PSP
+ - 224..233: INTM40-INTM49 banked outputs to PSP
+ - 256..383: 1:1 local peripheral interrupt output to SSP
+ - 384..393: INTM10-INTM19 banked outputs to SSP
+ - 400..407: Software interrupts from the PSP output to SSP
+ - 408..415: Software interrupts from the TSP output to SSP
+ - 426..553: 1:1 local peripheral interrupt output to TSP
+ - 554..563: INTM20-INTM29 banked outputs to TSP
+ - 570..577: Software interrupts from the PSP output to TSP
+ - 578..585: Software interrupts from the SSP output to TSP
+
+ Inputs and outputs for INTC1 instances are context-dependent. However, for the
+ first instance of INTC1, the (inclusive) output ranges are:
+
+ - 00..05: INTM0-INTM5
+ - 10..15: INTM10-INTM15
+ - 20..25: INTM20-INTM25
+ - 30..35: INTM30-INTM35
+ - 40..45: INTM40-INTM45
+ - 50..50: BootMCU
+
+maintainers:
+ - ryan_chen@aspeedtech.com
+ - andrew@codeconstruct.com.au
+
+properties:
+ compatible:
+ enum:
+ - aspeed,ast2700-intc0
+ - aspeed,ast2700-intc1
+
+ reg:
+ maxItems: 1
+
+ interrupt-controller: true
+
+ '#interrupt-cells':
+ const: 1
+ description: Single cell encoding the INTC local interrupt number (hwirq).
+
+ aspeed,interrupt-ranges:
+ description: |
+ Describes how ranges of controller output pins are routed to a parent
+ interrupt controller.
+
+ Each range entry is encoded as:
+
+ <out count phandle parent-specifier...>
+
+ where:
+ - out: First controller interrupt output index in the range.
+ - count: Number of consecutive controller interrupt outputs and parent
+ interrupt inputs in this range.
+ - phandle: Phandle to the parent interrupt controller node.
+ - parent-specifier: Interrupt specifier, as defined by the parent
+ interrupt controller binding.
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ minItems: 3
+ items:
+ description: Range descriptors with a parent interrupt specifier.
+
+required:
+ - compatible
+ - reg
+ - interrupt-controller
+ - '#interrupt-cells'
+ - aspeed,interrupt-ranges
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ interrupt-controller@12100000 {
+ compatible = "aspeed,ast2700-intc0";
+ reg = <0x12100000 0x3b00>;
+ interrupt-parent = <&gic>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ aspeed,interrupt-ranges =
+ <0 128 &gic GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
+ <144 8 &gic GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
+ <152 8 &gic GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>,
+ <192 10 &gic GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>,
+ <208 10 &gic GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>,
+ <224 10 &gic GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>,
+ <256 128 &ssp_nvic 0 0>,
+ <384 10 &ssp_nvic 160 0>,
+ <400 8 &ssp_nvic 144 0>,
+ <408 8 &ssp_nvic 152 0>,
+ <426 128 &tsp_nvic 0 0>,
+ <554 10 &tsp_nvic 160 0>,
+ <570 8 &tsp_nvic 144 0>,
+ <578 8 &tsp_nvic 152 0>;
+ };
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 2/5] irqchip/ast2700-intc: Add AST2700-A2 support
2026-03-06 8:07 [PATCH v2 0/5] AST2700-A2 interrupt controller hierarchy and route support Ryan Chen
2026-03-06 8:07 ` [PATCH v2 1/5] dt-bindings: interrupt-controller: aspeed: Add AST2700-A2 support Ryan Chen
@ 2026-03-06 8:07 ` Ryan Chen
2026-03-06 8:07 ` [PATCH v2 3/5] irqchip/ast2700-intc: Add KUnit tests for route resolution Ryan Chen
` (2 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Ryan Chen @ 2026-03-06 8:07 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Joel Stanley,
Andrew Jeffery, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Thomas Gleixner, Thomas Gleixner
Cc: linux-kernel, devicetree, linux-arm-kernel, linux-aspeed,
linux-riscv, Ryan Chen
The AST2700 interrupt fabric is shared by multiple integrated processors
(PSP/SSP/TSP/BootMCU), each with its own interrupt controller and its own
devicetree view of the system. As a result, interrupt routing cannot be
treated as fixed: the valid route for a peripheral interrupt depends on
which processor is consuming it.
The INTC0 driver models this by creating a hierarchical irqdomain under
the upstream interrupt controller selected by the interrupt-parent
property in the devicetree. Information derived from this relationship
is incorporated into the route resolution logic for the controller.
The INTC1 driver implements the banked INTM-fed controller and forwards
interrupts toward INTC0, without embedding assumptions about the final
destination processor.
Signed-off-by: Ryan Chen <ryan_chen@aspeedtech.com>
---
Changes in v2:
- remove typedef u32 aspeed_intc_output_t
- modify #include <asm-generic/errno.h> to <linux/err.h>
- add newline after include "irq-ast2700.h"
- make defines tabular
- Struct declarations should align the struct member names in a table
- modify raw_spinlock_irqsave() to raw_spin_lock()
- use u32 ier replace mask/unmask
- remove pointless line break
- refine aspeed_intc0_routes, aspeed_intc1_routes array
- remove range_contains_element(), use in_range32()
- remove dev_dbg()
- remove EXPORT_SYMBOL_GPL(aspeed_intc0_resolve_route);
- make irq_set_chip_and_handler() with one line
- replace magic constants to macro define
- move struct aspeed_intc0 to irq-ast2700.h
- add mcro define for upstream param
---
drivers/irqchip/Kconfig | 12 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-ast2700-intc0.c | 584 ++++++++++++++++++++++++++++++++++++
drivers/irqchip/irq-ast2700-intc1.c | 282 +++++++++++++++++
drivers/irqchip/irq-ast2700.c | 106 +++++++
drivers/irqchip/irq-ast2700.h | 47 +++
6 files changed, 1032 insertions(+)
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index f07b00d7fef9..0156fee89b2c 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -110,6 +110,18 @@ config AL_FIC
help
Support Amazon's Annapurna Labs Fabric Interrupt Controller.
+config ASPEED_AST2700_INTC
+ bool "ASPEED AST2700 Interrupt Controller support"
+ depends on OF
+ depends on ARCH_ASPEED || COMPILE_TEST
+ select IRQ_DOMAIN_HIERARCHY
+ help
+ Enable support for the ASPEED AST2700 interrupt controller.
+ This driver handles interrupt, routing and merged interrupt
+ sources to upstream parent interrupt controllers.
+
+ If unsure, say N.
+
config ATMEL_AIC_IRQ
bool
select GENERIC_IRQ_CHIP
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 26aa3b6ec99f..62790663f982 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -89,6 +89,7 @@ obj-$(CONFIG_MVEBU_PIC) += irq-mvebu-pic.o
obj-$(CONFIG_MVEBU_SEI) += irq-mvebu-sei.o
obj-$(CONFIG_LS_EXTIRQ) += irq-ls-extirq.o
obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
+obj-$(CONFIG_ASPEED_AST2700_INTC) += irq-ast2700.o irq-ast2700-intc0.o irq-ast2700-intc1.o
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o irq-aspeed-scu-ic.o
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-intc.o
obj-$(CONFIG_STM32MP_EXTI) += irq-stm32mp-exti.o
diff --git a/drivers/irqchip/irq-ast2700-intc0.c b/drivers/irqchip/irq-ast2700-intc0.c
new file mode 100644
index 000000000000..66e2fb108281
--- /dev/null
+++ b/drivers/irqchip/irq-ast2700-intc0.c
@@ -0,0 +1,584 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Aspeed AST2700 Interrupt Controller.
+ *
+ * Copyright (C) 2026 ASPEED Technology Inc.
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/fwnode.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kconfig.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/overflow.h>
+#include <linux/property.h>
+#include <linux/spinlock.h>
+
+#include "irq-ast2700.h"
+
+#define INT_NUM 480
+#define INTM_NUM 50
+#define SWINT_NUM 16
+
+#define INTM_BASE (INT_NUM)
+#define SWINT_BASE (INT_NUM + INTM_NUM)
+#define INT0_NUM (INT_NUM + INTM_NUM + SWINT_NUM)
+
+#define INTC0_IN_NUM 480
+#define INTC0_ROUTE_NUM 5
+#define INTC0_INTM_NUM 50
+#define INTC0_ROUTE_BITS 3
+
+#define GIC_P2P_SPI_END 128
+#define INTC0_SWINT_OUT_BASE 144
+
+#define INTC0_SWINT_IER 0x10
+#define INTC0_SWINT_ISR 0x14
+#define INTC0_INTBANKX_IER 0x1000
+#define INTC0_INTBANK_SIZE 0x100
+#define INTC0_INTBANK_GROUPS 11
+#define INTC0_INTBANKS_PER_GRP 3
+#define INTC0_INTMX_IER 0x1b00
+#define INTC0_INTMX_ISR 0x1b04
+#define INTC0_INTMX_BANK_SIZE 0x10
+#define INTC0_INTM_BANK_NUM 3
+#define INTC0_IRQS_PER_BANK 32
+#define INTM_IRQS_PER_BANK 10
+#define INTC0_SEL_BASE 0x200
+#define INTC0_SEL_BANK_SIZE 0x4
+#define INTC0_SEL_ROUTE_SIZE 0x100
+
+static void aspeed_swint_irq_mask(struct irq_data *data)
+{
+ struct aspeed_intc0 *intc0 = irq_data_get_irq_chip_data(data);
+ int bit = data->hwirq - SWINT_BASE;
+ u32 ier;
+
+ guard(raw_spinlock)(&intc0->intc_lock);
+ ier = readl(intc0->base + INTC0_SWINT_IER) & ~BIT(bit);
+ writel(ier, intc0->base + INTC0_SWINT_IER);
+ irq_chip_mask_parent(data);
+}
+
+static void aspeed_swint_irq_unmask(struct irq_data *data)
+{
+ struct aspeed_intc0 *intc0 = irq_data_get_irq_chip_data(data);
+ int bit = data->hwirq - SWINT_BASE;
+ u32 ier;
+
+ guard(raw_spinlock)(&intc0->intc_lock);
+ ier = readl(intc0->base + INTC0_SWINT_IER) | BIT(bit);
+ writel(ier, intc0->base + INTC0_SWINT_IER);
+ irq_chip_unmask_parent(data);
+}
+
+static void aspeed_swint_irq_eoi(struct irq_data *data)
+{
+ struct aspeed_intc0 *intc0 = irq_data_get_irq_chip_data(data);
+ int bit = data->hwirq - SWINT_BASE;
+
+ writel(BIT(bit), intc0->base + INTC0_SWINT_ISR);
+ irq_chip_eoi_parent(data);
+}
+
+static struct irq_chip aspeed_swint_chip = {
+ .name = "ast2700-swint",
+ .irq_eoi = aspeed_swint_irq_eoi,
+ .irq_mask = aspeed_swint_irq_mask,
+ .irq_unmask = aspeed_swint_irq_unmask,
+ .irq_set_affinity = irq_chip_set_affinity_parent,
+ .flags = IRQCHIP_SET_TYPE_MASKED,
+};
+
+static void aspeed_intc0_irq_mask(struct irq_data *data)
+{
+ struct aspeed_intc0 *intc0 = irq_data_get_irq_chip_data(data);
+ int bank = (data->hwirq - INTM_BASE) / INTM_IRQS_PER_BANK;
+ int bit = (data->hwirq - INTM_BASE) % INTM_IRQS_PER_BANK;
+ u32 ier;
+
+ guard(raw_spinlock)(&intc0->intc_lock);
+ ier = readl(intc0->base + INTC0_INTMX_IER + bank * INTC0_INTMX_BANK_SIZE) & ~BIT(bit);
+ writel(ier, intc0->base + INTC0_INTMX_IER + bank * INTC0_INTMX_BANK_SIZE);
+ irq_chip_mask_parent(data);
+}
+
+static void aspeed_intc0_irq_unmask(struct irq_data *data)
+{
+ struct aspeed_intc0 *intc0 = irq_data_get_irq_chip_data(data);
+ int bank = (data->hwirq - INTM_BASE) / INTM_IRQS_PER_BANK;
+ int bit = (data->hwirq - INTM_BASE) % INTM_IRQS_PER_BANK;
+ u32 ier;
+
+ guard(raw_spinlock)(&intc0->intc_lock);
+ ier = readl(intc0->base + INTC0_INTMX_IER + bank * INTC0_INTMX_BANK_SIZE) | BIT(bit);
+ writel(ier, intc0->base + INTC0_INTMX_IER + bank * INTC0_INTMX_BANK_SIZE);
+ irq_chip_unmask_parent(data);
+}
+
+static void aspeed_intc0_irq_eoi(struct irq_data *data)
+{
+ struct aspeed_intc0 *intc0 = irq_data_get_irq_chip_data(data);
+ int bank = (data->hwirq - INTM_BASE) / INTM_IRQS_PER_BANK;
+ int bit = (data->hwirq - INTM_BASE) % INTM_IRQS_PER_BANK;
+
+ writel(BIT(bit), intc0->base + INTC0_INTMX_ISR + bank * INTC0_INTMX_BANK_SIZE);
+ irq_chip_eoi_parent(data);
+}
+
+static struct irq_chip aspeed_intm_chip = {
+ .name = "ast2700-intmerge",
+ .irq_eoi = aspeed_intc0_irq_eoi,
+ .irq_mask = aspeed_intc0_irq_mask,
+ .irq_unmask = aspeed_intc0_irq_unmask,
+ .irq_set_affinity = irq_chip_set_affinity_parent,
+ .flags = IRQCHIP_SET_TYPE_MASKED,
+};
+
+static struct irq_chip linear_intr_irq_chip = {
+ .name = "ast2700-int",
+ .irq_eoi = irq_chip_eoi_parent,
+ .irq_mask = irq_chip_mask_parent,
+ .irq_unmask = irq_chip_unmask_parent,
+ .irq_set_affinity = irq_chip_set_affinity_parent,
+ .flags = IRQCHIP_SET_TYPE_MASKED,
+};
+
+static const u32 aspeed_intc0_routes[INTC0_IN_NUM / INTC0_IRQS_PER_BANK][INTC0_ROUTE_NUM] = {
+ { 0, 256, 426, AST2700_INTC_INVALID_ROUTE, AST2700_INTC_INVALID_ROUTE },
+ { 32, 288, 458, AST2700_INTC_INVALID_ROUTE, AST2700_INTC_INVALID_ROUTE },
+ { 64, 320, 490, AST2700_INTC_INVALID_ROUTE, AST2700_INTC_INVALID_ROUTE },
+ { 96, 352, 522, AST2700_INTC_INVALID_ROUTE, AST2700_INTC_INVALID_ROUTE },
+ { 128, 384, 554, 160, 176 },
+ { 129, 385, 555, 161, 177 },
+ { 130, 386, 556, 162, 178 },
+ { 131, 387, 557, 163, 179 },
+ { 132, 388, 558, 164, 180 },
+ { 133, 544, 714, 165, 181 },
+ { 134, 545, 715, 166, 182 },
+ { 135, 546, 706, 167, 183 },
+ { 136, 547, 707, 168, 184 },
+ { 137, 548, 708, 169, 185 },
+ { 138, 549, 709, 170, 186 },
+};
+
+static const u32 aspeed_intc0_intm_routes[INTC0_INTM_NUM / INTM_IRQS_PER_BANK] = {
+ 192, 416, 586, 208, 224
+};
+
+static int resolve_input_from_child_ranges(const struct aspeed_intc0 *intc0,
+ const struct aspeed_intc_interrupt_range *range,
+ u32 outpin, u32 *input)
+{
+ u32 offset, base;
+
+ if (!in_range32(outpin, range->start, range->count))
+ return -ENOENT;
+
+ if (range->upstream.param_count == 0)
+ return -EINVAL;
+
+ base = range->upstream.param[ASPEED_INTC_RANGES_BASE];
+ offset = outpin - range->start;
+ if (check_add_overflow(base, offset, input)) {
+ dev_warn(intc0->dev, "%s: Arithmetic overflow for input derivation: %u + %u\n",
+ __func__, base, offset);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int resolve_parent_range_for_output(const struct aspeed_intc0 *intc0,
+ const struct fwnode_handle *parent,
+ u32 output,
+ struct aspeed_intc_interrupt_range *resolved)
+{
+ for (size_t i = 0; i < intc0->ranges.nranges; i++) {
+ struct aspeed_intc_interrupt_range range =
+ intc0->ranges.ranges[i];
+
+ if (!in_range32(output, range.start, range.count))
+ continue;
+
+ if (range.upstream.fwnode != parent)
+ continue;
+
+ if (resolved) {
+ resolved->start = output;
+ resolved->count = 1;
+ resolved->upstream = range.upstream;
+ resolved->upstream.param[ASPEED_INTC_RANGES_COUNT] +=
+ output - range.start;
+ }
+
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
+static int resolve_parent_route_for_input(const struct aspeed_intc0 *intc0,
+ const struct fwnode_handle *parent, u32 input,
+ struct aspeed_intc_interrupt_range *resolved)
+{
+ int rc = -ENOENT;
+ u32 c0o;
+
+ if (input < INT_NUM) {
+ static_assert(INTC0_ROUTE_NUM < INT_MAX, "Broken cast");
+ for (size_t i = 0; rc == -ENOENT && i < INTC0_ROUTE_NUM; i++) {
+ c0o = aspeed_intc0_routes[input / INTC0_IRQS_PER_BANK][i];
+ if (c0o == AST2700_INTC_INVALID_ROUTE)
+ continue;
+
+ if (input < GIC_P2P_SPI_END)
+ c0o += input % INTC0_IRQS_PER_BANK;
+
+ rc = resolve_parent_range_for_output(intc0, parent, c0o, resolved);
+ if (!rc)
+ return (int)i;
+ }
+ } else if (input < (INT_NUM + INTM_NUM)) {
+ c0o = aspeed_intc0_intm_routes[(input - INT_NUM) / INTM_IRQS_PER_BANK];
+ c0o += ((input - INT_NUM) % INTM_IRQS_PER_BANK);
+ return resolve_parent_range_for_output(intc0, parent, c0o, resolved);
+ } else if (input < (INT_NUM + INTM_NUM + SWINT_NUM)) {
+ c0o = input - SWINT_BASE + INTC0_SWINT_OUT_BASE;
+ return resolve_parent_range_for_output(intc0, parent, c0o, resolved);
+ } else {
+ return -ENOENT;
+ }
+
+ return rc;
+}
+
+/**
+ * aspeed_intc0_resolve_route - Determine the necessary interrupt output at intc1
+ * @c0domain: The pointer to intc0's irq_domain
+ * @nc1outs: The number of valid intc1 outputs available for the input
+ * @c1outs: The array of available intc1 output indices for the input
+ * @nc1ranges: The number of interrupt range entries for intc1
+ * @c1ranges: The array of configured intc1 interrupt ranges
+ * @resolved: The fully resolved range entry after applying the resolution
+ * algorithm
+ *
+ * Returns: The intc1 route index associated with the intc1 output identified in
+ * @resolved on success. Otherwise, a negative errno value.
+ *
+ * The AST2700 interrupt architecture allows any peripheral interrupt source
+ * to be routed to one of up to four processors running in the SoC. A processor
+ * binding a driver for a peripheral that requests an interrupt is (without
+ * further design and effort) the destination for the requested interrupt.
+ *
+ * Routing a peripheral interrupt to its destination processor requires
+ * coordination between INTC0 on the CPU die and one or more INTC1 instances.
+ * At least one INTC1 instance exists in the SoC on the IO-die, however up
+ * to two more instances may be integrated via LTPI (LVDS Tunneling Protocol
+ * & Interface).
+ *
+ * Between the multiple destinations, various route constraints, and the
+ * devicetree binding design, some information that's needed at INTC1 instances
+ * to route inbound interrupts correctly to the destination processor is only
+ * available at INTC0.
+ *
+ * aspeed_intc0_resolve_route() is to be invoked by INTC1 driver instances to
+ * perform the route resolution. The implementation in INTC0 allows INTC0 to
+ * encapsulate the information used to perform route selection, and provides it
+ * with an opportunity to apply policy as part of the selection process. Such
+ * policy may, for instance, choose to de-prioritise some interrupts destined
+ * for the PSP (Primary Service Processor) GIC.
+ */
+int aspeed_intc0_resolve_route(const struct irq_domain *c0domain, size_t nc1outs,
+ const u32 *c1outs, size_t nc1ranges,
+ const struct aspeed_intc_interrupt_range *c1ranges,
+ struct aspeed_intc_interrupt_range *resolved)
+{
+ struct fwnode_handle *parent_fwnode;
+ struct aspeed_intc0 *intc0;
+ int ret;
+
+ if (!c0domain || !resolved)
+ return -EINVAL;
+
+ if (nc1outs > INT_MAX)
+ return -EINVAL;
+
+ if (nc1outs == 0 || nc1ranges == 0)
+ return -ENOENT;
+
+ if (!fwnode_device_is_compatible(c0domain->fwnode, "aspeed,ast2700-intc0"))
+ return -ENODEV;
+
+ intc0 = c0domain->host_data;
+ if (!intc0)
+ return -EINVAL;
+
+ parent_fwnode = of_fwnode_handle(intc0->parent);
+
+ for (size_t i = 0; i < nc1outs; i++) {
+ u32 c1o = c1outs[i];
+
+ if (c1o == AST2700_INTC_INVALID_ROUTE)
+ continue;
+
+ for (size_t j = 0; j < nc1ranges; j++) {
+ struct aspeed_intc_interrupt_range c1r = c1ranges[j];
+ u32 input;
+
+ /*
+ * Range match for intc1 output pin
+ *
+ * Assume a failed match is still a match for the purpose of testing,
+ * saves a bunch of mess in the test fixtures
+ */
+ if (!(c0domain == irq_find_matching_fwspec(&c1r.upstream,
+ c0domain->bus_token) ||
+ IS_ENABLED(CONFIG_ASPEED_AST2700_INTC_TEST)))
+ continue;
+
+ ret = resolve_input_from_child_ranges(intc0, &c1r, c1o, &input);
+ if (ret)
+ continue;
+
+ /*
+ * INTC1 should never request routes for peripheral interrupt sources
+ * directly attached to INTC0.
+ */
+ if (input < GIC_P2P_SPI_END)
+ continue;
+
+ ret = resolve_parent_route_for_input(intc0, parent_fwnode, input, NULL);
+ if (ret < 0)
+ continue;
+
+ /* Route resolution succeeded */
+ resolved->start = c1o;
+ resolved->count = 1;
+ resolved->upstream = c1r.upstream;
+ resolved->upstream.param[ASPEED_INTC_RANGES_BASE] = input;
+ /* Cast protected by prior test against nc1outs */
+ return (int)i;
+ }
+ }
+
+ return -ENOENT;
+}
+
+static int aspeed_intc0_irq_domain_map(struct irq_domain *domain,
+ unsigned int irq, irq_hw_number_t hwirq)
+{
+ if (hwirq < GIC_P2P_SPI_END)
+ irq_set_chip_and_handler(irq, &linear_intr_irq_chip, handle_level_irq);
+ else if (hwirq < INTM_BASE)
+ return -EINVAL;
+ else if (hwirq < SWINT_BASE)
+ irq_set_chip_and_handler(irq, &aspeed_intm_chip, handle_level_irq);
+ else if (hwirq < INT0_NUM)
+ irq_set_chip_and_handler(irq, &aspeed_swint_chip, handle_level_irq);
+ else
+ return -EINVAL;
+
+ irq_set_chip_data(irq, domain->host_data);
+ return 0;
+}
+
+static int aspeed_intc0_irq_domain_translate(struct irq_domain *domain,
+ struct irq_fwspec *fwspec,
+ unsigned long *hwirq,
+ unsigned int *type)
+{
+ if (fwspec->param_count != 1)
+ return -EINVAL;
+
+ *hwirq = fwspec->param[0];
+ *type = IRQ_TYPE_NONE;
+ return 0;
+}
+
+static int aspeed_intc0_irq_domain_alloc(struct irq_domain *domain,
+ unsigned int virq,
+ unsigned int nr_irqs, void *data)
+{
+ struct aspeed_intc0 *intc0 = domain->host_data;
+ struct aspeed_intc_interrupt_range resolved;
+ struct irq_fwspec *fwspec = data;
+ struct irq_fwspec parent_fwspec;
+ struct irq_chip *chip;
+ unsigned long hwirq;
+ unsigned int type;
+ int ret;
+
+ ret = aspeed_intc0_irq_domain_translate(domain, fwspec, &hwirq, &type);
+ if (ret)
+ return ret;
+
+ if (hwirq >= GIC_P2P_SPI_END && hwirq < INT_NUM)
+ return -EINVAL;
+
+ if (hwirq < INTM_BASE)
+ chip = &linear_intr_irq_chip;
+ else if (hwirq < SWINT_BASE)
+ chip = &aspeed_intm_chip;
+ else
+ chip = &aspeed_swint_chip;
+
+ ret = resolve_parent_route_for_input(intc0, domain->parent->fwnode,
+ (u32)hwirq, &resolved);
+ if (ret)
+ return ret;
+
+ parent_fwspec = resolved.upstream;
+ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
+ &parent_fwspec);
+ if (ret)
+ return ret;
+
+ for (int i = 0; i < nr_irqs; ++i, ++hwirq, ++virq) {
+ ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip,
+ domain->host_data);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int aspeed_intc0_irq_domain_activate(struct irq_domain *domain,
+ struct irq_data *data, bool reserve)
+{
+ struct aspeed_intc0 *intc0 = irq_data_get_irq_chip_data(data);
+ unsigned long hwirq = data->hwirq;
+ int route, bank, bit;
+ u32 mask;
+
+ if (hwirq >= INT0_NUM)
+ return -EINVAL;
+
+ if (in_range32(hwirq, INTM_BASE, INTM_NUM + SWINT_NUM))
+ return 0;
+
+ bank = hwirq / INTC0_IRQS_PER_BANK;
+ bit = hwirq % INTC0_IRQS_PER_BANK;
+ mask = BIT(bit);
+
+ route = resolve_parent_route_for_input(intc0, intc0->local->parent->fwnode,
+ hwirq, NULL);
+ if (route < 0)
+ return route;
+
+ guard(raw_spinlock)(&intc0->intc_lock);
+ for (int i = 0; i < INTC0_ROUTE_BITS; i++) {
+ void __iomem *sel = intc0->base + INTC0_SEL_BASE +
+ (bank * INTC0_SEL_BANK_SIZE) +
+ (INTC0_SEL_ROUTE_SIZE * i);
+ u32 reg = readl(sel);
+
+ if (route & BIT(i))
+ reg |= mask;
+ else
+ reg &= ~mask;
+
+ writel(reg, sel);
+ if (readl(sel) != reg)
+ return -EACCES;
+ }
+
+ return 0;
+}
+
+static const struct irq_domain_ops aspeed_intc0_irq_domain_ops = {
+ .translate = aspeed_intc0_irq_domain_translate,
+ .activate = aspeed_intc0_irq_domain_activate,
+ .alloc = aspeed_intc0_irq_domain_alloc,
+ .free = irq_domain_free_irqs_common,
+ .map = aspeed_intc0_irq_domain_map,
+};
+
+static void aspeed_intc0_disable_swint(struct aspeed_intc0 *intc0)
+{
+ writel(0, intc0->base + INTC0_SWINT_IER);
+}
+
+static void aspeed_intc0_disable_intbank(struct aspeed_intc0 *intc0)
+{
+ for (int i = 0; i < INTC0_INTBANK_GROUPS; i++) {
+ for (int j = 0; j < INTC0_INTBANKS_PER_GRP; j++) {
+ u32 base = INTC0_INTBANKX_IER +
+ (INTC0_INTBANK_SIZE * i) +
+ (INTC0_INTMX_BANK_SIZE * j);
+
+ writel(0, intc0->base + base);
+ }
+ }
+}
+
+static void aspeed_intc0_disable_intm(struct aspeed_intc0 *intc0)
+{
+ for (int i = 0; i < INTC0_INTM_BANK_NUM; i++)
+ writel(0, intc0->base + INTC0_INTMX_IER + (INTC0_INTMX_BANK_SIZE * i));
+}
+
+static int aspeed_intc0_probe(struct platform_device *pdev,
+ struct device_node *parent)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct irq_domain *parent_domain;
+ struct aspeed_intc0 *intc0;
+ int ret;
+
+ if (!parent) {
+ pr_err("missing parent interrupt node\n");
+ return -ENODEV;
+ }
+
+ intc0 = devm_kzalloc(&pdev->dev, sizeof(*intc0), GFP_KERNEL);
+ if (!intc0)
+ return -ENOMEM;
+
+ intc0->dev = &pdev->dev;
+ intc0->parent = parent;
+ intc0->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(intc0->base))
+ return PTR_ERR(intc0->base);
+
+ aspeed_intc0_disable_swint(intc0);
+ aspeed_intc0_disable_intbank(intc0);
+ aspeed_intc0_disable_intm(intc0);
+
+ raw_spin_lock_init(&intc0->intc_lock);
+
+ parent_domain = irq_find_host(parent);
+ if (!parent_domain) {
+ pr_err("unable to obtain parent domain\n");
+ return -ENODEV;
+ }
+
+ if (!of_device_is_compatible(parent, "arm,gic-v3"))
+ return -ENODEV;
+
+ intc0->local = irq_domain_create_hierarchy(parent_domain, 0, INT0_NUM,
+ of_fwnode_handle(node),
+ &aspeed_intc0_irq_domain_ops,
+ intc0);
+ if (!intc0->local)
+ return -ENOMEM;
+
+ ret = aspeed_intc_populate_ranges(&pdev->dev, &intc0->ranges);
+ if (ret < 0) {
+ irq_domain_remove(intc0->local);
+ return ret;
+ }
+
+ return 0;
+}
+
+IRQCHIP_PLATFORM_DRIVER_BEGIN(ast2700_intc0)
+IRQCHIP_MATCH("aspeed,ast2700-intc0", aspeed_intc0_probe)
+IRQCHIP_PLATFORM_DRIVER_END(ast2700_intc0)
diff --git a/drivers/irqchip/irq-ast2700-intc1.c b/drivers/irqchip/irq-ast2700-intc1.c
new file mode 100644
index 000000000000..09b9d5d743e6
--- /dev/null
+++ b/drivers/irqchip/irq-ast2700-intc1.c
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Aspeed AST2700 Interrupt Controller.
+ *
+ * Copyright (C) 2026 ASPEED Technology Inc.
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/spinlock.h>
+
+#include "irq-ast2700.h"
+
+#define INTC1_IER 0x100
+#define INTC1_ISR 0x104
+#define INTC1_BANK_SIZE 0x10
+#define INTC1_SEL_BASE 0x80
+#define INTC1_SEL_BANK_SIZE 0x4
+#define INTC1_SEL_ROUTE_SIZE 0x20
+#define INTC1_IRQS_PER_BANK 32
+#define INTC1_BANK_NUM 6
+#define INTC1_ROUTE_NUM 7
+#define INTC1_IN_NUM 192
+#define INTC1_BOOTMCU_ROUTE 6
+#define INTC1_ROUTE_SELECTOR_BITS 3
+#define INTC1_ROUTE_IRQS_PER_GROUP 32
+#define INTC1_ROUTE_SHIFT 5
+
+struct aspeed_intc1 {
+ struct device *dev;
+ void __iomem *base;
+ raw_spinlock_t intc_lock;
+ struct irq_domain *local;
+ struct irq_domain *upstream;
+ struct aspeed_intc_interrupt_ranges ranges;
+};
+
+static void aspeed_intc1_disable_int(struct aspeed_intc1 *intc1)
+{
+ for (int i = 0; i < INTC1_BANK_NUM; i++)
+ writel(0, intc1->base + INTC1_IER + (INTC1_BANK_SIZE * i));
+}
+
+static void aspeed_intc1_irq_handler(struct irq_desc *desc)
+{
+ struct aspeed_intc1 *intc1 = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ unsigned long bit, status;
+
+ chained_irq_enter(chip, desc);
+
+ for (int bank = 0; bank < INTC1_BANK_NUM; bank++) {
+ status = readl(intc1->base + INTC1_ISR + (INTC1_BANK_SIZE * bank));
+ if (!status)
+ continue;
+
+ for_each_set_bit(bit, &status, INTC1_IRQS_PER_BANK) {
+ generic_handle_domain_irq(intc1->local, (bank * INTC1_IRQS_PER_BANK) + bit);
+ writel(BIT(bit), intc1->base + INTC1_ISR + (INTC1_BANK_SIZE * bank));
+ }
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static void aspeed_intc1_irq_mask(struct irq_data *data)
+{
+ struct aspeed_intc1 *intc1 = irq_data_get_irq_chip_data(data);
+ int bank = data->hwirq / INTC1_IRQS_PER_BANK;
+ int bit = data->hwirq % INTC1_IRQS_PER_BANK;
+ u32 ier;
+
+ guard(raw_spinlock)(&intc1->intc_lock);
+ ier = readl(intc1->base + INTC1_IER + (INTC1_BANK_SIZE * bank)) & ~BIT(bit);
+ writel(ier, intc1->base + INTC1_IER + (INTC1_BANK_SIZE * bank));
+}
+
+static void aspeed_intc1_irq_unmask(struct irq_data *data)
+{
+ struct aspeed_intc1 *intc1 = irq_data_get_irq_chip_data(data);
+ int bank = data->hwirq / INTC1_IRQS_PER_BANK;
+ int bit = data->hwirq % INTC1_IRQS_PER_BANK;
+ u32 ier;
+
+ guard(raw_spinlock)(&intc1->intc_lock);
+ ier = readl(intc1->base + INTC1_IER + (INTC1_BANK_SIZE * bank)) | BIT(bit);
+ writel(ier, intc1->base + INTC1_IER + (INTC1_BANK_SIZE * bank));
+}
+
+static struct irq_chip aspeed_intc_chip = {
+ .name = "ASPEED INTC1",
+ .irq_mask = aspeed_intc1_irq_mask,
+ .irq_unmask = aspeed_intc1_irq_unmask,
+};
+
+static int aspeed_intc1_irq_domain_translate(struct irq_domain *domain,
+ struct irq_fwspec *fwspec,
+ unsigned long *hwirq,
+ unsigned int *type)
+{
+ if (fwspec->param_count != 1)
+ return -EINVAL;
+
+ *hwirq = fwspec->param[0];
+ *type = IRQ_TYPE_LEVEL_HIGH;
+ return 0;
+}
+
+static int aspeed_intc1_map_irq_domain(struct irq_domain *domain,
+ unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ irq_domain_set_info(domain, irq, hwirq, &aspeed_intc_chip,
+ domain->host_data, handle_level_irq, NULL, NULL);
+ return 0;
+}
+
+/*
+ * In-bound interrupts are progressively merged into one out-bound interrupt in
+ * groups of 32. Apply this fact to compress the route table in corresponding
+ * groups of 32.
+ */
+static const u32
+aspeed_intc1_routes[INTC1_IN_NUM / INTC1_ROUTE_IRQS_PER_GROUP][INTC1_ROUTE_NUM] = {
+ { 0, AST2700_INTC_INVALID_ROUTE, 10, 20, 30, 40, 50 },
+ { 1, AST2700_INTC_INVALID_ROUTE, 11, 21, 31, 41, 50 },
+ { 2, AST2700_INTC_INVALID_ROUTE, 12, 22, 32, 42, 50 },
+ { 3, AST2700_INTC_INVALID_ROUTE, 13, 23, 33, 43, 50 },
+ { 4, AST2700_INTC_INVALID_ROUTE, 14, 24, 34, 44, 50 },
+ { 5, AST2700_INTC_INVALID_ROUTE, 15, 25, 35, 45, 50 },
+};
+
+static int aspeed_intc1_irq_domain_activate(struct irq_domain *domain,
+ struct irq_data *data, bool reserve)
+{
+ struct aspeed_intc1 *intc1 = irq_data_get_irq_chip_data(data);
+ struct aspeed_intc_interrupt_range resolved;
+ int rc, bank, bit;
+ u32 mask;
+
+ if (WARN_ON_ONCE((data->hwirq >> INTC1_ROUTE_SHIFT) >= ARRAY_SIZE(aspeed_intc1_routes)))
+ return -EINVAL;
+
+ /*
+ * outpin may be an error if the upstream is the BootMCU APLIC node, or
+ * anything except a valid intc0 driver instance
+ */
+ rc = aspeed_intc0_resolve_route(intc1->upstream, INTC1_ROUTE_NUM,
+ aspeed_intc1_routes[data->hwirq >> INTC1_ROUTE_SHIFT],
+ intc1->ranges.nranges,
+ intc1->ranges.ranges, &resolved);
+ if (rc < 0) {
+ if (!fwnode_device_is_compatible(intc1->upstream->fwnode, "riscv,aplic")) {
+ dev_warn(intc1->dev,
+ "Failed to resolve interrupt route for hwirq %lu in domain %s\n",
+ data->hwirq, domain->name);
+ return rc;
+ }
+ rc = INTC1_BOOTMCU_ROUTE;
+ }
+
+ bank = data->hwirq / INTC1_IRQS_PER_BANK;
+ bit = data->hwirq % INTC1_IRQS_PER_BANK;
+ mask = BIT(bit);
+
+ guard(raw_spinlock)(&intc1->intc_lock);
+ for (int i = 0; i < INTC1_ROUTE_SELECTOR_BITS; i++) {
+ void __iomem *sel = intc1->base + INTC1_SEL_BASE +
+ (bank * INTC1_SEL_BANK_SIZE) +
+ (INTC1_SEL_ROUTE_SIZE * i);
+ u32 reg = readl(sel);
+
+ if (rc & BIT(i))
+ reg |= mask;
+ else
+ reg &= ~mask;
+
+ writel(reg, sel);
+ if (readl(sel) != reg)
+ return -EACCES;
+ }
+
+ return 0;
+}
+
+static const struct irq_domain_ops aspeed_intc1_irq_domain_ops = {
+ .map = aspeed_intc1_map_irq_domain,
+ .translate = aspeed_intc1_irq_domain_translate,
+ .activate = aspeed_intc1_irq_domain_activate,
+};
+
+static void aspeed_intc1_request_interrupts(struct aspeed_intc1 *intc1)
+{
+ for (unsigned int i = 0; i < intc1->ranges.nranges; i++) {
+ struct aspeed_intc_interrupt_range *r =
+ &intc1->ranges.ranges[i];
+
+ if (intc1->upstream !=
+ irq_find_matching_fwspec(&r->upstream,
+ intc1->upstream->bus_token))
+ continue;
+
+ for (u32 k = 0; k < r->count; k++) {
+ struct of_phandle_args parent_irq;
+ int irq;
+
+ parent_irq.np = to_of_node(r->upstream.fwnode);
+ parent_irq.args_count = 1;
+ parent_irq.args[0] =
+ intc1->ranges.ranges[i].upstream.param[ASPEED_INTC_RANGES_BASE] + k;
+
+ irq = irq_create_of_mapping(&parent_irq);
+ if (!irq)
+ continue;
+
+ irq_set_chained_handler_and_data(irq,
+ aspeed_intc1_irq_handler, intc1);
+ }
+ }
+}
+
+static int aspeed_intc1_probe(struct platform_device *pdev,
+ struct device_node *parent)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct aspeed_intc1 *intc1;
+ struct irq_domain *host;
+ int ret;
+
+ if (!parent) {
+ dev_err(&pdev->dev, "missing parent interrupt node\n");
+ return -ENODEV;
+ }
+
+ if (!of_device_is_compatible(parent, "aspeed,ast2700-intc0"))
+ return -ENODEV;
+
+ host = irq_find_host(parent);
+ if (!host)
+ return -ENODEV;
+
+ intc1 = devm_kzalloc(&pdev->dev, sizeof(*intc1), GFP_KERNEL);
+ if (!intc1)
+ return -ENOMEM;
+
+ intc1->dev = &pdev->dev;
+ intc1->upstream = host;
+ intc1->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(intc1->base))
+ return PTR_ERR(intc1->base);
+
+ aspeed_intc1_disable_int(intc1);
+
+ raw_spin_lock_init(&intc1->intc_lock);
+
+ intc1->local = irq_domain_create_linear(of_fwnode_handle(node),
+ INTC1_BANK_NUM * INTC1_IRQS_PER_BANK,
+ &aspeed_intc1_irq_domain_ops, intc1);
+ if (!intc1->local)
+ return -ENOMEM;
+
+ ret = aspeed_intc_populate_ranges(&pdev->dev, &intc1->ranges);
+ if (ret < 0) {
+ irq_domain_remove(intc1->local);
+ return ret;
+ }
+
+ aspeed_intc1_request_interrupts(intc1);
+
+ return 0;
+}
+
+IRQCHIP_PLATFORM_DRIVER_BEGIN(ast2700_intc1)
+IRQCHIP_MATCH("aspeed,ast2700-intc1", aspeed_intc1_probe)
+IRQCHIP_PLATFORM_DRIVER_END(ast2700_intc1)
diff --git a/drivers/irqchip/irq-ast2700.c b/drivers/irqchip/irq-ast2700.c
new file mode 100644
index 000000000000..280657480d5f
--- /dev/null
+++ b/drivers/irqchip/irq-ast2700.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Aspeed AST2700 Interrupt Controller.
+ *
+ * Copyright (C) 2026 ASPEED Technology Inc.
+ */
+#include "irq-ast2700.h"
+
+#define ASPEED_INTC_RANGE_FIXED_CELLS 3U
+#define ASPEED_INTC_RANGE_OFF_START 0U
+#define ASPEED_INTC_RANGE_OFF_COUNT 1U
+#define ASPEED_INTC_RANGE_OFF_PHANDLE 2U
+
+/**
+ * aspeed_intc_populate_ranges
+ * @dev: Device owning the interrupt controller node.
+ * @ranges: Destination for parsed range descriptors.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int aspeed_intc_populate_ranges(struct device *dev,
+ struct aspeed_intc_interrupt_ranges *ranges)
+{
+ struct aspeed_intc_interrupt_range *arr;
+ const __be32 *pvs, *pve;
+ struct device_node *dn;
+ int len;
+
+ if (!dev || !ranges)
+ return -EINVAL;
+
+ dn = dev->of_node;
+
+ pvs = of_get_property(dn, "aspeed,interrupt-ranges", &len);
+ if (!pvs)
+ return -EINVAL;
+
+ if (len % sizeof(__be32))
+ return -EINVAL;
+
+ /* Over-estimate the range entry count for now */
+ ranges->ranges = devm_kmalloc_array(dev,
+ len / (ASPEED_INTC_RANGE_FIXED_CELLS * sizeof(__be32)),
+ sizeof(*ranges->ranges),
+ GFP_KERNEL);
+ if (!ranges->ranges)
+ return -ENOMEM;
+
+ pve = pvs + (len / sizeof(__be32));
+ for (unsigned int i = 0; pve - pvs >= ASPEED_INTC_RANGE_FIXED_CELLS; i++) {
+ struct aspeed_intc_interrupt_range *r;
+ struct device_node *target;
+ u32 target_cells;
+
+ target = of_find_node_by_phandle(be32_to_cpu(pvs[ASPEED_INTC_RANGE_OFF_PHANDLE]));
+ if (!target)
+ return -EINVAL;
+
+ if (of_property_read_u32(target, "#interrupt-cells",
+ &target_cells)) {
+ of_node_put(target);
+ return -EINVAL;
+ }
+
+ if (!target_cells || target_cells > IRQ_DOMAIN_IRQ_SPEC_PARAMS) {
+ of_node_put(target);
+ return -EINVAL;
+ }
+
+ if (pve - pvs < ASPEED_INTC_RANGE_FIXED_CELLS + target_cells) {
+ of_node_put(target);
+ return -EINVAL;
+ }
+
+ r = &ranges->ranges[i];
+ r->start = be32_to_cpu(pvs[ASPEED_INTC_RANGE_OFF_START]);
+ r->count = be32_to_cpu(pvs[ASPEED_INTC_RANGE_OFF_COUNT]);
+
+ {
+ struct of_phandle_args args = {
+ .np = target,
+ .args_count = target_cells,
+ };
+
+ for (u32 j = 0; j < target_cells; j++)
+ args.args[j] = be32_to_cpu(pvs[ASPEED_INTC_RANGE_FIXED_CELLS + j]);
+
+ of_phandle_args_to_fwspec(target, args.args,
+ args.args_count,
+ &r->upstream);
+ }
+
+ of_node_put(target);
+ pvs += ASPEED_INTC_RANGE_FIXED_CELLS + target_cells;
+ ranges->nranges++;
+ }
+
+ /* Re-fit the range array now we know the entry count */
+ arr = devm_krealloc_array(dev, ranges->ranges, ranges->nranges,
+ sizeof(*ranges->ranges), GFP_KERNEL);
+ if (!arr)
+ return -ENOMEM;
+ ranges->ranges = arr;
+
+ return 0;
+}
diff --git a/drivers/irqchip/irq-ast2700.h b/drivers/irqchip/irq-ast2700.h
new file mode 100644
index 000000000000..544f1af4c8ab
--- /dev/null
+++ b/drivers/irqchip/irq-ast2700.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Aspeed AST2700 Interrupt Controller.
+ *
+ * Copyright (C) 2026 ASPEED Technology Inc.
+ */
+#ifndef DRIVERS_IRQCHIP_AST2700
+#define DRIVERS_IRQCHIP_AST2700
+
+#include <linux/device.h>
+#include <linux/irqdomain.h>
+
+#define AST2700_INTC_INVALID_ROUTE (~0U)
+#define ASPEED_INTC_RANGES_BASE 0U
+#define ASPEED_INTC_RANGES_COUNT 1U
+
+struct aspeed_intc_interrupt_range {
+ u32 start;
+ u32 count;
+ struct irq_fwspec upstream;
+};
+
+struct aspeed_intc_interrupt_ranges {
+ struct aspeed_intc_interrupt_range *ranges;
+ unsigned int nranges;
+};
+
+struct aspeed_intc0 {
+ struct device *dev;
+ void __iomem *base;
+ raw_spinlock_t intc_lock;
+ struct irq_domain *local;
+ struct device_node *parent;
+ struct aspeed_intc_interrupt_ranges ranges;
+};
+
+int aspeed_intc_populate_ranges(struct device *dev,
+ struct aspeed_intc_interrupt_ranges *ranges);
+
+int aspeed_intc0_resolve_route(const struct irq_domain *c0domain,
+ size_t nc1outs,
+ const u32 *c1outs,
+ size_t nc1ranges,
+ const struct aspeed_intc_interrupt_range *c1ranges,
+ struct aspeed_intc_interrupt_range *resolved);
+
+#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 3/5] irqchip/ast2700-intc: Add KUnit tests for route resolution
2026-03-06 8:07 [PATCH v2 0/5] AST2700-A2 interrupt controller hierarchy and route support Ryan Chen
2026-03-06 8:07 ` [PATCH v2 1/5] dt-bindings: interrupt-controller: aspeed: Add AST2700-A2 support Ryan Chen
2026-03-06 8:07 ` [PATCH v2 2/5] irqchip/ast2700-intc: " Ryan Chen
@ 2026-03-06 8:07 ` Ryan Chen
2026-03-06 8:07 ` [PATCH v2 4/5] irqchip/aspeed-intc: Remove AST2700-A0 support Ryan Chen
2026-03-06 8:07 ` [PATCH v2 5/5] dt-bindings: interrupt-controller: aspeed: " Ryan Chen
4 siblings, 0 replies; 9+ messages in thread
From: Ryan Chen @ 2026-03-06 8:07 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Joel Stanley,
Andrew Jeffery, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Thomas Gleixner, Thomas Gleixner
Cc: linux-kernel, devicetree, linux-arm-kernel, linux-aspeed,
linux-riscv, Ryan Chen
Add a KUnit suite for aspeed_intc0_resolve_route().
Cover invalid arguments, invalid domain/range data, connected and
disconnected mappings, and malformed upstream range cases.
Signed-off-by: Ryan Chen <ryan_chen@aspeedtech.com>
---
Changes in v2:
- add line break before include "irq-ast2700.h"
- remove pointless newline.
- rename arm_gicv3_fwnode_read_string_array to
gicv3_fwnode_read_string_array
- add .kunitconfig file
---
drivers/irqchip/.kunitconfig | 5 +
drivers/irqchip/Kconfig | 11 +
drivers/irqchip/Makefile | 1 +
drivers/irqchip/irq-ast2700-intc0-test.c | 473 +++++++++++++++++++++++++++++++
4 files changed, 490 insertions(+)
diff --git a/drivers/irqchip/.kunitconfig b/drivers/irqchip/.kunitconfig
new file mode 100644
index 000000000000..00a12703f635
--- /dev/null
+++ b/drivers/irqchip/.kunitconfig
@@ -0,0 +1,5 @@
+CONFIG_KUNIT=y
+CONFIG_OF=y
+CONFIG_COMPILE_TEST=y
+CONFIG_ASPEED_AST2700_INTC=y
+CONFIG_ASPEED_AST2700_INTC_TEST=y
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 0156fee89b2c..143af3f30a4b 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -122,6 +122,17 @@ config ASPEED_AST2700_INTC
If unsure, say N.
+config ASPEED_AST2700_INTC_TEST
+ bool "Tests for the ASPEED AST2700 Interrupt Controller"
+ depends on ASPEED_AST2700_INTC && KUNIT=y
+ default KUNIT_ALL_TESTS
+ help
+ Enable KUnit tests for AST2700 INTC route resolution.
+ The tests exercise error handling and route selection paths.
+ This option is intended for test builds.
+
+ If unsure, say N.
+
config ATMEL_AIC_IRQ
bool
select GENERIC_IRQ_CHIP
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 62790663f982..ac04a4b97797 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -90,6 +90,7 @@ obj-$(CONFIG_MVEBU_SEI) += irq-mvebu-sei.o
obj-$(CONFIG_LS_EXTIRQ) += irq-ls-extirq.o
obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
obj-$(CONFIG_ASPEED_AST2700_INTC) += irq-ast2700.o irq-ast2700-intc0.o irq-ast2700-intc1.o
+obj-$(CONFIG_ASPEED_AST2700_INTC_TEST) += irq-ast2700-intc0-test.o
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o irq-aspeed-scu-ic.o
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-intc.o
obj-$(CONFIG_STM32MP_EXTI) += irq-stm32mp-exti.o
diff --git a/drivers/irqchip/irq-ast2700-intc0-test.c b/drivers/irqchip/irq-ast2700-intc0-test.c
new file mode 100644
index 000000000000..2aa00df72c04
--- /dev/null
+++ b/drivers/irqchip/irq-ast2700-intc0-test.c
@@ -0,0 +1,473 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Code Construct
+ */
+#include <kunit/test.h>
+
+#include "irq-ast2700.h"
+
+static void aspeed_intc0_resolve_route_bad_args(struct kunit *test)
+{
+ static const struct aspeed_intc_interrupt_range c1ranges[] = { 0 };
+ static const u32 c1outs[] = { 0 };
+ struct aspeed_intc_interrupt_range resolved;
+ const struct irq_domain c0domain = { 0 };
+ int rc;
+
+ rc = aspeed_intc0_resolve_route(NULL, 0, c1outs, 0, c1ranges, NULL);
+ KUNIT_EXPECT_EQ(test, rc, -EINVAL);
+
+ rc = aspeed_intc0_resolve_route(&c0domain, 0, c1outs,
+ ARRAY_SIZE(c1ranges), c1ranges,
+ &resolved);
+ KUNIT_EXPECT_EQ(test, rc, -ENOENT);
+
+ rc = aspeed_intc0_resolve_route(&c0domain, ARRAY_SIZE(c1outs), c1outs,
+ 0, c1ranges, &resolved);
+ KUNIT_EXPECT_EQ(test, rc, -ENOENT);
+}
+
+static int gicv3_fwnode_read_string_array(const struct fwnode_handle *fwnode,
+ const char *propname, const char **val, size_t nval)
+{
+ if (!propname)
+ return -EINVAL;
+
+ if (!val)
+ return 1;
+
+ if (WARN_ON(nval != 1))
+ return -EOVERFLOW;
+
+ *val = "arm,gic-v3";
+ return 1;
+}
+
+static const struct fwnode_operations arm_gicv3_fwnode_ops = {
+ .property_read_string_array = gicv3_fwnode_read_string_array,
+};
+
+static void aspeed_intc_resolve_route_invalid_c0domain(struct kunit *test)
+{
+ struct device_node intc0_node = {
+ .fwnode = { .ops = &arm_gicv3_fwnode_ops },
+ };
+ const struct irq_domain c0domain = { .fwnode = &intc0_node.fwnode };
+ static const struct aspeed_intc_interrupt_range c1ranges[] = { 0 };
+ static const u32 c1outs[] = { 0 };
+ struct aspeed_intc_interrupt_range resolved;
+ int rc;
+
+ rc = aspeed_intc0_resolve_route(&c0domain, ARRAY_SIZE(c1outs), c1outs,
+ ARRAY_SIZE(c1ranges), c1ranges,
+ &resolved);
+ KUNIT_EXPECT_NE(test, rc, 0);
+}
+
+static int
+aspeed_intc0_fwnode_read_string_array(const struct fwnode_handle *fwnode_handle,
+ const char *propname, const char **val,
+ size_t nval)
+{
+ if (!propname)
+ return -EINVAL;
+
+ if (!val)
+ return 1;
+
+ if (WARN_ON(nval != 1))
+ return -EOVERFLOW;
+
+ *val = "aspeed,ast2700-intc0";
+ return nval;
+}
+
+static const struct fwnode_operations intc0_fwnode_ops = {
+ .property_read_string_array = aspeed_intc0_fwnode_read_string_array,
+};
+
+static void
+aspeed_intc0_resolve_route_c1i1o1c0i1o1_connected(struct kunit *test)
+{
+ struct device_node intc0_node = {
+ .fwnode = { .ops = &intc0_fwnode_ops },
+ };
+ struct aspeed_intc_interrupt_range c1ranges[] = {
+ {
+ .start = 0,
+ .count = 1,
+ .upstream = {
+ .fwnode = &intc0_node.fwnode,
+ .param_count = 1,
+ .param = { 128 }
+ }
+ }
+ };
+ static const u32 c1outs[] = { 0 };
+ struct aspeed_intc_interrupt_range resolved;
+ struct aspeed_intc_interrupt_range intc0_ranges[] = {
+ {
+ .start = 128,
+ .count = 1,
+ .upstream = {
+ .fwnode = NULL,
+ .param_count = 0,
+ .param = { 0 },
+ }
+ }
+ };
+ struct aspeed_intc0 intc0 = {
+ .ranges = { .ranges = intc0_ranges, .nranges = ARRAY_SIZE(intc0_ranges), }
+ };
+ const struct irq_domain c0domain = {
+ .host_data = &intc0,
+ .fwnode = &intc0_node.fwnode
+ };
+ int rc;
+
+ rc = aspeed_intc0_resolve_route(&c0domain, ARRAY_SIZE(c1outs), c1outs,
+ ARRAY_SIZE(c1ranges), c1ranges,
+ &resolved);
+ KUNIT_EXPECT_EQ(test, rc, 0);
+ KUNIT_EXPECT_EQ(test, resolved.start, 0);
+ KUNIT_EXPECT_EQ(test, resolved.count, 1);
+ KUNIT_EXPECT_EQ(test, resolved.upstream.param[0], 128);
+}
+
+static void
+aspeed_intc0_resolve_route_c1i1o1c0i1o1_disconnected(struct kunit *test)
+{
+ struct device_node intc0_node = {
+ .fwnode = { .ops = &intc0_fwnode_ops },
+ };
+ struct aspeed_intc_interrupt_range c1ranges[] = {
+ {
+ .start = 0,
+ .count = 1,
+ .upstream = {
+ .fwnode = &intc0_node.fwnode,
+ .param_count = 1,
+ .param = { 128 }
+ }
+ }
+ };
+ static const u32 c1outs[] = { 0 };
+ struct aspeed_intc_interrupt_range resolved;
+ struct aspeed_intc_interrupt_range intc0_ranges[] = {
+ {
+ .start = 129,
+ .count = 1,
+ .upstream = {
+ .fwnode = NULL,
+ .param_count = 0,
+ .param = { 0 },
+ }
+ }
+ };
+ struct aspeed_intc0 intc0 = {
+ .ranges = {
+ .ranges = intc0_ranges,
+ .nranges = ARRAY_SIZE(intc0_ranges),
+ }
+ };
+ const struct irq_domain c0domain = {
+ .host_data = &intc0,
+ .fwnode = &intc0_node.fwnode
+ };
+ int rc;
+
+ rc = aspeed_intc0_resolve_route(&c0domain, ARRAY_SIZE(c1outs), c1outs,
+ ARRAY_SIZE(c1ranges), c1ranges,
+ &resolved);
+ KUNIT_EXPECT_NE(test, rc, 0);
+}
+
+static void aspeed_intc0_resolve_route_c1i1o1mc0i1o1(struct kunit *test)
+{
+ struct device_node intc0_node = {
+ .fwnode = { .ops = &intc0_fwnode_ops },
+ };
+ struct aspeed_intc_interrupt_range c1ranges[] = {
+ {
+ .start = 0,
+ .count = 1,
+ .upstream = {
+ .fwnode = &intc0_node.fwnode,
+ .param_count = 1,
+ .param = { 480 }
+ }
+ }
+ };
+ static const u32 c1outs[] = { 0 };
+ struct aspeed_intc_interrupt_range resolved;
+ struct aspeed_intc_interrupt_range intc0_ranges[] = {
+ {
+ .start = 192,
+ .count = 1,
+ .upstream = {
+ .fwnode = NULL,
+ .param_count = 0,
+ .param = { 0 },
+ }
+ }
+ };
+ struct aspeed_intc0 intc0 = {
+ .ranges = {
+ .ranges = intc0_ranges,
+ .nranges = ARRAY_SIZE(intc0_ranges),
+ }
+ };
+ const struct irq_domain c0domain = {
+ .host_data = &intc0,
+ .fwnode = &intc0_node.fwnode
+ };
+ int rc;
+
+ rc = aspeed_intc0_resolve_route(&c0domain, ARRAY_SIZE(c1outs), c1outs,
+ ARRAY_SIZE(c1ranges), c1ranges,
+ &resolved);
+ KUNIT_EXPECT_EQ(test, rc, 0);
+ KUNIT_EXPECT_EQ(test, resolved.start, 0);
+ KUNIT_EXPECT_EQ(test, resolved.count, 1);
+ KUNIT_EXPECT_EQ(test, resolved.upstream.param[0], 480);
+}
+
+static void aspeed_intc0_resolve_route_c1i2o2mc0i1o1(struct kunit *test)
+{
+ struct device_node intc0_node = {
+ .fwnode = { .ops = &intc0_fwnode_ops },
+ };
+ struct aspeed_intc_interrupt_range c1ranges[] = {
+ {
+ .start = 0,
+ .count = 1,
+ .upstream = {
+ .fwnode = &intc0_node.fwnode,
+ .param_count = 1,
+ .param = { 480 }
+ }
+ },
+ {
+ .start = 1,
+ .count = 1,
+ .upstream = {
+ .fwnode = &intc0_node.fwnode,
+ .param_count = 1,
+ .param = { 510 }
+ }
+ }
+ };
+ static const u32 c1outs[] = { 1 };
+ struct aspeed_intc_interrupt_range resolved;
+ struct aspeed_intc_interrupt_range intc0_ranges[] = {
+ {
+ .start = 208,
+ .count = 1,
+ .upstream = {
+ .fwnode = NULL,
+ .param_count = 0,
+ .param = { 0 },
+ }
+ }
+ };
+ struct aspeed_intc0 intc0 = {
+ .ranges = {
+ .ranges = intc0_ranges,
+ .nranges = ARRAY_SIZE(intc0_ranges),
+ }
+ };
+ const struct irq_domain c0domain = {
+ .host_data = &intc0,
+ .fwnode = &intc0_node.fwnode
+ };
+ int rc;
+
+ rc = aspeed_intc0_resolve_route(&c0domain, ARRAY_SIZE(c1outs), c1outs,
+ ARRAY_SIZE(c1ranges), c1ranges,
+ &resolved);
+ KUNIT_EXPECT_EQ(test, rc, 0);
+ KUNIT_EXPECT_EQ(test, resolved.start, 1);
+ KUNIT_EXPECT_EQ(test, resolved.count, 1);
+ KUNIT_EXPECT_EQ(test, resolved.upstream.param[0], 510);
+}
+
+static void aspeed_intc0_resolve_route_c1i1o1mc0i2o1(struct kunit *test)
+{
+ struct device_node intc0_node = {
+ .fwnode = { .ops = &intc0_fwnode_ops },
+ };
+ struct aspeed_intc_interrupt_range c1ranges[] = {
+ {
+ .start = 0,
+ .count = 1,
+ .upstream = {
+ .fwnode = &intc0_node.fwnode,
+ .param_count = 1,
+ .param = { 510 }
+ }
+ },
+ };
+ static const u32 c1outs[] = { 0 };
+ struct aspeed_intc_interrupt_range resolved;
+ struct aspeed_intc_interrupt_range intc0_ranges[] = {
+ {
+ .start = 192,
+ .count = 1,
+ .upstream = {
+ .fwnode = NULL,
+ .param_count = 0,
+ .param = {0},
+ }
+ },
+ {
+ .start = 208,
+ .count = 1,
+ .upstream = {
+ .fwnode = NULL,
+ .param_count = 0,
+ .param = {0},
+ }
+ }
+ };
+ struct aspeed_intc0 intc0 = {
+ .ranges = {
+ .ranges = intc0_ranges,
+ .nranges = ARRAY_SIZE(intc0_ranges),
+ }
+ };
+ const struct irq_domain c0domain = {
+ .host_data = &intc0,
+ .fwnode = &intc0_node.fwnode
+ };
+ int rc;
+
+ rc = aspeed_intc0_resolve_route(&c0domain, ARRAY_SIZE(c1outs), c1outs,
+ ARRAY_SIZE(c1ranges), c1ranges,
+ &resolved);
+ KUNIT_EXPECT_EQ(test, rc, 0);
+ KUNIT_EXPECT_EQ(test, resolved.start, 0);
+ KUNIT_EXPECT_EQ(test, resolved.count, 1);
+ KUNIT_EXPECT_EQ(test, resolved.upstream.param[0], 510);
+}
+
+static void aspeed_intc0_resolve_route_c1i1o2mc0i1o1_invalid(struct kunit *test)
+{
+ struct device_node intc0_node = {
+ .fwnode = { .ops = &intc0_fwnode_ops },
+ };
+ struct aspeed_intc_interrupt_range c1ranges[] = {
+ {
+ .start = 0,
+ .count = 1,
+ .upstream = {
+ .fwnode = &intc0_node.fwnode,
+ .param_count = 1,
+ .param = { 480 }
+ }
+ }
+ };
+ static const u32 c1outs[] = {
+ AST2700_INTC_INVALID_ROUTE, 0
+ };
+ struct aspeed_intc_interrupt_range resolved;
+ struct aspeed_intc_interrupt_range intc0_ranges[] = {
+ {
+ .start = 192,
+ .count = 1,
+ .upstream = {
+ .fwnode = NULL,
+ .param_count = 0,
+ .param = { 0 },
+ }
+ }
+ };
+ struct aspeed_intc0 intc0 = {
+ .ranges = {
+ .ranges = intc0_ranges,
+ .nranges = ARRAY_SIZE(intc0_ranges),
+ }
+ };
+ const struct irq_domain c0domain = {
+ .host_data = &intc0,
+ .fwnode = &intc0_node.fwnode
+ };
+ int rc;
+
+ rc = aspeed_intc0_resolve_route(&c0domain, ARRAY_SIZE(c1outs), c1outs,
+ ARRAY_SIZE(c1ranges), c1ranges,
+ &resolved);
+ KUNIT_EXPECT_EQ(test, rc, 1);
+ KUNIT_EXPECT_EQ(test, resolved.start, 0);
+ KUNIT_EXPECT_EQ(test, resolved.count, 1);
+ KUNIT_EXPECT_EQ(test, resolved.upstream.param[0], 480);
+}
+
+static void
+aspeed_intc0_resolve_route_c1i1o1mc0i1o1_bad_range_upstream(struct kunit *test)
+{
+ struct device_node intc0_node = {
+ .fwnode = { .ops = &intc0_fwnode_ops },
+ };
+ struct aspeed_intc_interrupt_range c1ranges[] = {
+ {
+ .start = 0,
+ .count = 1,
+ .upstream = {
+ .fwnode = &intc0_node.fwnode,
+ .param_count = 0,
+ .param = { 0 }
+ }
+ }
+ };
+ static const u32 c1outs[] = { 0 };
+ struct aspeed_intc_interrupt_range resolved;
+ struct aspeed_intc_interrupt_range intc0_ranges[] = {
+ {
+ .start = 0,
+ .count = 0,
+ .upstream = {
+ .fwnode = NULL,
+ .param_count = 0,
+ .param = { 0 },
+ }
+ }
+ };
+ struct aspeed_intc0 intc0 = {
+ .ranges = {
+ .ranges = intc0_ranges,
+ .nranges = ARRAY_SIZE(intc0_ranges),
+ }
+ };
+ const struct irq_domain c0domain = {
+ .host_data = &intc0,
+ .fwnode = &intc0_node.fwnode
+ };
+ int rc;
+
+ rc = aspeed_intc0_resolve_route(&c0domain, ARRAY_SIZE(c1outs), c1outs,
+ ARRAY_SIZE(c1ranges), c1ranges,
+ &resolved);
+ KUNIT_EXPECT_NE(test, rc, 0);
+}
+
+static struct kunit_case ast2700_intc0_test_cases[] = {
+ KUNIT_CASE(aspeed_intc0_resolve_route_bad_args),
+ KUNIT_CASE(aspeed_intc_resolve_route_invalid_c0domain),
+ KUNIT_CASE(aspeed_intc0_resolve_route_c1i1o1c0i1o1_connected),
+ KUNIT_CASE(aspeed_intc0_resolve_route_c1i1o1c0i1o1_disconnected),
+ KUNIT_CASE(aspeed_intc0_resolve_route_c1i1o1mc0i1o1),
+ KUNIT_CASE(aspeed_intc0_resolve_route_c1i2o2mc0i1o1),
+ KUNIT_CASE(aspeed_intc0_resolve_route_c1i1o1mc0i2o1),
+ KUNIT_CASE(aspeed_intc0_resolve_route_c1i1o2mc0i1o1_invalid),
+ KUNIT_CASE(aspeed_intc0_resolve_route_c1i1o1mc0i1o1_bad_range_upstream),
+ {},
+};
+
+static struct kunit_suite ast2700_intc0_test_suite = {
+ .name = "ast2700-intc0",
+ .test_cases = ast2700_intc0_test_cases,
+};
+
+kunit_test_suite(ast2700_intc0_test_suite);
+
+MODULE_LICENSE("GPL");
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 4/5] irqchip/aspeed-intc: Remove AST2700-A0 support
2026-03-06 8:07 [PATCH v2 0/5] AST2700-A2 interrupt controller hierarchy and route support Ryan Chen
` (2 preceding siblings ...)
2026-03-06 8:07 ` [PATCH v2 3/5] irqchip/ast2700-intc: Add KUnit tests for route resolution Ryan Chen
@ 2026-03-06 8:07 ` Ryan Chen
2026-03-06 8:07 ` [PATCH v2 5/5] dt-bindings: interrupt-controller: aspeed: " Ryan Chen
4 siblings, 0 replies; 9+ messages in thread
From: Ryan Chen @ 2026-03-06 8:07 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Joel Stanley,
Andrew Jeffery, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Thomas Gleixner, Thomas Gleixner
Cc: linux-kernel, devicetree, linux-arm-kernel, linux-aspeed,
linux-riscv, Ryan Chen
The existing AST2700 interrupt controller driver
("aspeed,ast2700-intc-ic") was written against the A0 pre-production
design.
From A1 onwards (retained in the A2 production silicon), the interrupt
fabric was re-architected: interrupt routing is programmable and
interrupt outputs can be directed to multiple upstream controllers
(PSP GIC, Secondary Service Processor (SSP) NVIC, Tertiary Service
Processor (TSP) NVIC, and Boot MCU interrupt controller). This design
requires route resolution and a controller hierarchy model which the
A0 driver cannot represent.
Remove driver support for A0 in favour of the driver for the A2
production design.
Signed-off-by: Ryan Chen <ryan_chen@aspeedtech.com>
---
drivers/irqchip/Makefile | 1 -
drivers/irqchip/irq-aspeed-intc.c | 139 --------------------------------------
2 files changed, 140 deletions(-)
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index ac04a4b97797..3d02441b3ee6 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -92,7 +92,6 @@ obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
obj-$(CONFIG_ASPEED_AST2700_INTC) += irq-ast2700.o irq-ast2700-intc0.o irq-ast2700-intc1.o
obj-$(CONFIG_ASPEED_AST2700_INTC_TEST) += irq-ast2700-intc0-test.o
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o irq-aspeed-scu-ic.o
-obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-intc.o
obj-$(CONFIG_STM32MP_EXTI) += irq-stm32mp-exti.o
obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o
obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o
diff --git a/drivers/irqchip/irq-aspeed-intc.c b/drivers/irqchip/irq-aspeed-intc.c
deleted file mode 100644
index 4fb0dd8349da..000000000000
--- a/drivers/irqchip/irq-aspeed-intc.c
+++ /dev/null
@@ -1,139 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Aspeed Interrupt Controller.
- *
- * Copyright (C) 2023 ASPEED Technology Inc.
- */
-
-#include <linux/bitops.h>
-#include <linux/irq.h>
-#include <linux/irqchip.h>
-#include <linux/irqchip/chained_irq.h>
-#include <linux/irqdomain.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/io.h>
-#include <linux/spinlock.h>
-
-#define INTC_INT_ENABLE_REG 0x00
-#define INTC_INT_STATUS_REG 0x04
-#define INTC_IRQS_PER_WORD 32
-
-struct aspeed_intc_ic {
- void __iomem *base;
- raw_spinlock_t gic_lock;
- raw_spinlock_t intc_lock;
- struct irq_domain *irq_domain;
-};
-
-static void aspeed_intc_ic_irq_handler(struct irq_desc *desc)
-{
- struct aspeed_intc_ic *intc_ic = irq_desc_get_handler_data(desc);
- struct irq_chip *chip = irq_desc_get_chip(desc);
-
- chained_irq_enter(chip, desc);
-
- scoped_guard(raw_spinlock, &intc_ic->gic_lock) {
- unsigned long bit, status;
-
- status = readl(intc_ic->base + INTC_INT_STATUS_REG);
- for_each_set_bit(bit, &status, INTC_IRQS_PER_WORD) {
- generic_handle_domain_irq(intc_ic->irq_domain, bit);
- writel(BIT(bit), intc_ic->base + INTC_INT_STATUS_REG);
- }
- }
-
- chained_irq_exit(chip, desc);
-}
-
-static void aspeed_intc_irq_mask(struct irq_data *data)
-{
- struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data);
- unsigned int mask = readl(intc_ic->base + INTC_INT_ENABLE_REG) & ~BIT(data->hwirq);
-
- guard(raw_spinlock)(&intc_ic->intc_lock);
- writel(mask, intc_ic->base + INTC_INT_ENABLE_REG);
-}
-
-static void aspeed_intc_irq_unmask(struct irq_data *data)
-{
- struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data);
- unsigned int unmask = readl(intc_ic->base + INTC_INT_ENABLE_REG) | BIT(data->hwirq);
-
- guard(raw_spinlock)(&intc_ic->intc_lock);
- writel(unmask, intc_ic->base + INTC_INT_ENABLE_REG);
-}
-
-static struct irq_chip aspeed_intc_chip = {
- .name = "ASPEED INTC",
- .irq_mask = aspeed_intc_irq_mask,
- .irq_unmask = aspeed_intc_irq_unmask,
-};
-
-static int aspeed_intc_ic_map_irq_domain(struct irq_domain *domain, unsigned int irq,
- irq_hw_number_t hwirq)
-{
- irq_set_chip_and_handler(irq, &aspeed_intc_chip, handle_level_irq);
- irq_set_chip_data(irq, domain->host_data);
-
- return 0;
-}
-
-static const struct irq_domain_ops aspeed_intc_ic_irq_domain_ops = {
- .map = aspeed_intc_ic_map_irq_domain,
-};
-
-static int __init aspeed_intc_ic_of_init(struct device_node *node,
- struct device_node *parent)
-{
- struct aspeed_intc_ic *intc_ic;
- int irq, i, ret = 0;
-
- intc_ic = kzalloc_obj(*intc_ic);
- if (!intc_ic)
- return -ENOMEM;
-
- intc_ic->base = of_iomap(node, 0);
- if (!intc_ic->base) {
- pr_err("Failed to iomap intc_ic base\n");
- ret = -ENOMEM;
- goto err_free_ic;
- }
- writel(0xffffffff, intc_ic->base + INTC_INT_STATUS_REG);
- writel(0x0, intc_ic->base + INTC_INT_ENABLE_REG);
-
- intc_ic->irq_domain = irq_domain_create_linear(of_fwnode_handle(node), INTC_IRQS_PER_WORD,
- &aspeed_intc_ic_irq_domain_ops, intc_ic);
- if (!intc_ic->irq_domain) {
- ret = -ENOMEM;
- goto err_iounmap;
- }
-
- raw_spin_lock_init(&intc_ic->gic_lock);
- raw_spin_lock_init(&intc_ic->intc_lock);
-
- /* Check all the irq numbers valid. If not, unmaps all the base and frees the data. */
- for (i = 0; i < of_irq_count(node); i++) {
- irq = irq_of_parse_and_map(node, i);
- if (!irq) {
- pr_err("Failed to get irq number\n");
- ret = -EINVAL;
- goto err_iounmap;
- }
- }
-
- for (i = 0; i < of_irq_count(node); i++) {
- irq = irq_of_parse_and_map(node, i);
- irq_set_chained_handler_and_data(irq, aspeed_intc_ic_irq_handler, intc_ic);
- }
-
- return 0;
-
-err_iounmap:
- iounmap(intc_ic->base);
-err_free_ic:
- kfree(intc_ic);
- return ret;
-}
-
-IRQCHIP_DECLARE(ast2700_intc_ic, "aspeed,ast2700-intc-ic", aspeed_intc_ic_of_init);
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 5/5] dt-bindings: interrupt-controller: aspeed: Remove AST2700-A0 support
2026-03-06 8:07 [PATCH v2 0/5] AST2700-A2 interrupt controller hierarchy and route support Ryan Chen
` (3 preceding siblings ...)
2026-03-06 8:07 ` [PATCH v2 4/5] irqchip/aspeed-intc: Remove AST2700-A0 support Ryan Chen
@ 2026-03-06 8:07 ` Ryan Chen
4 siblings, 0 replies; 9+ messages in thread
From: Ryan Chen @ 2026-03-06 8:07 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Joel Stanley,
Andrew Jeffery, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Thomas Gleixner, Thomas Gleixner
Cc: linux-kernel, devicetree, linux-arm-kernel, linux-aspeed,
linux-riscv, Ryan Chen
The existing AST2700 interrupt controller binding
("aspeed,ast2700-intc-ic") was written against the A0 pre-production
design.
In A0, the interrupt hierarchy effectively converged at the Primary
Service Processor (PSP): INTC1 instances fed into INTC0, and INTC0 was
wired to the PSP GIC. The binding therefore described a fixed, PSP
aggregation model.
From A1 onwards (retained in the A2 production silicon), the interrupt
fabric was re-architected: interrupt routing is programmable and
interrupt outputs can be directed to multiple upstream controllers
(PSP GIC, Secondary Service Processor (SSP) NVIC, Tertiary Service
Processor (TSP) NVIC, and Boot MCU interrupt controller). This design
requires route resolution and a controller hierarchy model which the
A0 binding cannot represent.
Remove the binding for the pre-production A0 design in favour of the
binding for the A2 production design. There is no significant user
impact from the removal as there are no existing devicetrees in any
of Linux, u-boot or Zephyr that make use of the A0 binding.
Signed-off-by: Ryan Chen <ryan_chen@aspeedtech.com>
---
.../interrupt-controller/aspeed,ast2700-intc.yaml | 90 ----------------------
1 file changed, 90 deletions(-)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2700-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2700-intc.yaml
deleted file mode 100644
index 258d21fe6e35..000000000000
--- a/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2700-intc.yaml
+++ /dev/null
@@ -1,90 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/interrupt-controller/aspeed,ast2700-intc.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Aspeed AST2700 Interrupt Controller
-
-description:
- This interrupt controller hardware is second level interrupt controller that
- is hooked to a parent interrupt controller. It's useful to combine multiple
- interrupt sources into 1 interrupt to parent interrupt controller.
-
-maintainers:
- - Kevin Chen <kevin_chen@aspeedtech.com>
-
-properties:
- compatible:
- enum:
- - aspeed,ast2700-intc-ic
-
- reg:
- maxItems: 1
-
- interrupt-controller: true
-
- '#interrupt-cells':
- const: 1
- description:
- The first cell is the IRQ number, the second cell is the trigger
- type as defined in interrupt.txt in this directory.
-
- interrupts:
- minItems: 1
- maxItems: 10
- description: |
- Depend to which INTC0 or INTC1 used.
- INTC0 and INTC1 are two kinds of interrupt controller with enable and raw
- status registers for use.
- INTC0 is used to assert GIC if interrupt in INTC1 asserted.
- INTC1 is used to assert INTC0 if interrupt of modules asserted.
- +-----+ +-------+ +---------+---module0
- | GIC |---| INTC0 |--+--| INTC1_0 |---module2
- | | | | | | |---...
- +-----+ +-------+ | +---------+---module31
- |
- | +---------+---module0
- +---| INTC1_1 |---module2
- | | |---...
- | +---------+---module31
- ...
- | +---------+---module0
- +---| INTC1_5 |---module2
- | |---...
- +---------+---module31
-
-required:
- - compatible
- - reg
- - interrupt-controller
- - '#interrupt-cells'
- - interrupts
-
-additionalProperties: false
-
-examples:
- - |
- #include <dt-bindings/interrupt-controller/arm-gic.h>
-
- bus {
- #address-cells = <2>;
- #size-cells = <2>;
-
- interrupt-controller@12101b00 {
- compatible = "aspeed,ast2700-intc-ic";
- reg = <0 0x12101b00 0 0x10>;
- #interrupt-cells = <1>;
- interrupt-controller;
- interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH>;
- };
- };
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v2 1/5] dt-bindings: interrupt-controller: aspeed: Add AST2700-A2 support
2026-03-06 8:07 ` [PATCH v2 1/5] dt-bindings: interrupt-controller: aspeed: Add AST2700-A2 support Ryan Chen
@ 2026-03-20 8:24 ` Thomas Gleixner
2026-03-23 19:07 ` Rob Herring
1 sibling, 0 replies; 9+ messages in thread
From: Thomas Gleixner @ 2026-03-20 8:24 UTC (permalink / raw)
To: Ryan Chen, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Joel Stanley, Andrew Jeffery, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti
Cc: linux-kernel, devicetree, linux-arm-kernel, linux-aspeed,
linux-riscv, Ryan Chen
On Fri, Mar 06 2026 at 16:07, Ryan Chen wrote:
> Introduce a new binding describing the AST2700 interrupt controller
> architecture implemented in the A2 production silicon.
>
> The AST2700 SoC has undergone multiple silicon revisions (A0, A1, A2)
> prior to mass production. The interrupt architecture was substantially
> reworked after the A0 revision for A1, and the A1 design is retained
> unchanged in the A2 production silicon.
>
> The existing AST2700 interrupt controller binding was written against
> the pre-production A0 design. That binding does not accurately describe
> the interrupt hierarchy and routing model present in A1/A2, where
> interrupts can be routed to multiple processor-local interrupt
> controllers (Primary Service Processor (PSP) GIC, Secondary Service
> Processor (SSP)/Tertiary Service Processor (TSP) NVICs, and BootMCU
> APLIC) depending on the execution context.
>
> Hardware connectivity between interrupt controllers is expressed using
> the aspeed,interrupt-ranges property.
Gentle reminder. Can the DT folks please have a look at this so we can
make progress here?
Thanks,
tglx
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 1/5] dt-bindings: interrupt-controller: aspeed: Add AST2700-A2 support
2026-03-06 8:07 ` [PATCH v2 1/5] dt-bindings: interrupt-controller: aspeed: Add AST2700-A2 support Ryan Chen
2026-03-20 8:24 ` Thomas Gleixner
@ 2026-03-23 19:07 ` Rob Herring
2026-03-24 2:24 ` Ryan Chen
1 sibling, 1 reply; 9+ messages in thread
From: Rob Herring @ 2026-03-23 19:07 UTC (permalink / raw)
To: Ryan Chen
Cc: Krzysztof Kozlowski, Conor Dooley, Joel Stanley, Andrew Jeffery,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Thomas Gleixner, linux-kernel, devicetree, linux-arm-kernel,
linux-aspeed, linux-riscv
On Fri, Mar 06, 2026 at 04:07:23PM +0800, Ryan Chen wrote:
> Introduce a new binding describing the AST2700 interrupt controller
> architecture implemented in the A2 production silicon.
>
> The AST2700 SoC has undergone multiple silicon revisions (A0, A1, A2)
> prior to mass production. The interrupt architecture was substantially
> reworked after the A0 revision for A1, and the A1 design is retained
> unchanged in the A2 production silicon.
>
> The existing AST2700 interrupt controller binding was written against
> the pre-production A0 design. That binding does not accurately describe
> the interrupt hierarchy and routing model present in A1/A2, where
> interrupts can be routed to multiple processor-local interrupt
> controllers (Primary Service Processor (PSP) GIC, Secondary Service
> Processor (SSP)/Tertiary Service Processor (TSP) NVICs, and BootMCU
> APLIC) depending on the execution context.
Unless you intend to maintain both bindings for some period, then you
should just squash the removal here. If both are going to be maintained
then patch 5 should not be applied yet.
>
> Hardware connectivity between interrupt controllers is expressed using
> the aspeed,interrupt-ranges property.
>
> Signed-off-by: Ryan Chen <ryan_chen@aspeedtech.com>
>
> ---
> Changes in v2:
> - Describe AST2700 A0/A1/A2 design evolution.
> - Drop the redundant '-ic' suffix from compatible strings.
> - Expand commit message to match the series cover letter context.
> - fix ascii diagram
> - remove intc0 label
> - remove spaces before >
> - drop intc1 example
> ---
> .../aspeed,ast2700-interrupt.yaml | 189 +++++++++++++++++++++
> 1 file changed, 189 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2700-interrupt.yaml b/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2700-interrupt.yaml
> new file mode 100644
> index 000000000000..13398ff8be12
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2700-interrupt.yaml
> @@ -0,0 +1,189 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/interrupt-controller/aspeed,ast2700-interrupt.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: ASPEED AST2700 Interrupt Controllers (INTC0/INTC1)
> +
> +description: |
> + The ASPEED AST2700 SoC integrates two interrupt controller designs:
> +
> + - INTC0: Primary controller that routes interrupt sources to upstream,
> + processor-specific interrupt controllers
> +
> + - INTC1: Secondary controller whose interrupt outputs feed into
> + INTC0
Wrap lines at 80 char.
> +
> + The SoC contains four processors to which interrupts can be routed:
> +
> + - PSP: Primary Service Processor (Cortex-A35)
> + - SSP: Secondary Service Processor (Cortex-M4)
> + - TSP: Tertiary Sevice Processor (Cortex-M4)
> + - BMCU: Boot MCU (a RISC-V microcontroller)
> +
> + The following diagram illustrates the overall architecture of the
> + ASPEED AST2700 interrupt controllers:
> +
> + +-----------+ +-----------+
> + | INTC0 | | INTC1(0) |
> + +-----------+ +-----------+
> + | Router | +-----------+ | Router |
> + | out int | +Peripheral + | out int |
> + +-----------+ | 0 0 <-+Controllers+ | INTM | +-----------+
> + |PSP GIC <-|---+ . . | +-----------+ | . . <-+Peripheral +
> + +-----------+ | . . | | . . | +Controllers+
> + +-----------+ | . . | | . . | +-----------+
> + |SSP NVIC <-|---+ . . <----------------+ . . |
> + +-----------+ | . . | | . . |
> + +-----------+ | . . <-------- | . . |
> + |TSP NVIC <-|---+ . . | | ----+ . . |
> + +-----------+ | . . | | | | O P |
> + | . . | | | +-----------+
> + | . . <---- | --------------------
> + | . . | | | +-----------+ |
> + | M N | | ---------+ INTC1(1) | |
> + +-----------+ | +-----------+ |
> + | . |
> + | +-----------+ |
> + -------------+ INTC1(N) | |
> + +-----------+ |
> + +--------------+ |
> + + BMCU APLIC <-+---------------------------------------------
> + +--------------+
> +
> + INTC0 supports:
> + - 128 local peripheral interrupt inputs
> + - Fan-in from up to three INTC1 instances via banked interrupt lines (INTM)
> + - Local peripheral interrupt outputs
> + - Merged interrupt outputs
> + - Software interrupt outputs (SWINT)
> + - Configurable interrupt routes targeting the PSP, SSP, and TSP
> +
> + INTC1 supports:
> + - 192 local peripheral interrupt inputs
> + - Banked interrupt outputs (INTM, 5 x 6 banks x 32 interrupts per bank)
> + - Configurable interrupt routes targeting the PSP, SSP, TSP, and BMCU
> +
> + One INTC1 instance is always present, on the SoC's IO die. A further two
> + instances may be attached to the SoC's one INTC0 instance via LTPI (LVDS
> + Tunneling Protocol & Interface).
> +
> + Interrupt numbering model
> + -------------------------
> + The binding uses a controller-local numbering model. Peripheral device
> + nodes use the INTCx local interrupt number (hwirq) in their 'interrupts' or
> + 'interrupts-extended' properties.
> +
> + For AST2700, INTC0 exposes the following (inclusive) input ranges:
> +
> + - 000..479: Independent interrupts
> + - 480..489: INTM0-INTM9
> + - 490..499: INTM10-INTM19
> + - 500..509: INTM20-INTM29
> + - 510..519: INTM30-INTM39
> + - 520..529: INTM40-INTM49
> +
> + INTC0's (inclusive) output ranges are as follows:
> +
> + - 000..127: 1:1 local peripheral interrupt output to PSP
> + - 144..151: Software interrupts from the SSP output to PSP
> + - 152..159: Software interrupts from the TSP output to PSP
> + - 192..201: INTM0-INTM9 banked outputs to PSP
> + - 208..217: INTM30-INTM39 banked outputs to PSP
> + - 224..233: INTM40-INTM49 banked outputs to PSP
> + - 256..383: 1:1 local peripheral interrupt output to SSP
> + - 384..393: INTM10-INTM19 banked outputs to SSP
> + - 400..407: Software interrupts from the PSP output to SSP
> + - 408..415: Software interrupts from the TSP output to SSP
> + - 426..553: 1:1 local peripheral interrupt output to TSP
> + - 554..563: INTM20-INTM29 banked outputs to TSP
> + - 570..577: Software interrupts from the PSP output to TSP
> + - 578..585: Software interrupts from the SSP output to TSP
> +
> + Inputs and outputs for INTC1 instances are context-dependent. However, for the
> + first instance of INTC1, the (inclusive) output ranges are:
> +
> + - 00..05: INTM0-INTM5
> + - 10..15: INTM10-INTM15
> + - 20..25: INTM20-INTM25
> + - 30..35: INTM30-INTM35
> + - 40..45: INTM40-INTM45
> + - 50..50: BootMCU
> +
> +maintainers:
> + - ryan_chen@aspeedtech.com
> + - andrew@codeconstruct.com.au
Name and email address please.
> +
> +properties:
> + compatible:
> + enum:
> + - aspeed,ast2700-intc0
> + - aspeed,ast2700-intc1
> +
> + reg:
> + maxItems: 1
> +
> + interrupt-controller: true
> +
> + '#interrupt-cells':
> + const: 1
> + description: Single cell encoding the INTC local interrupt number (hwirq).
> +
> + aspeed,interrupt-ranges:
> + description: |
> + Describes how ranges of controller output pins are routed to a parent
> + interrupt controller.
> +
> + Each range entry is encoded as:
> +
> + <out count phandle parent-specifier...>
> +
> + where:
> + - out: First controller interrupt output index in the range.
> + - count: Number of consecutive controller interrupt outputs and parent
> + interrupt inputs in this range.
> + - phandle: Phandle to the parent interrupt controller node.
> + - parent-specifier: Interrupt specifier, as defined by the parent
> + interrupt controller binding.
> + $ref: /schemas/types.yaml#/definitions/uint32-array
> + minItems: 3
> + items:
> + description: Range descriptors with a parent interrupt specifier.
> +
> +required:
> + - compatible
> + - reg
> + - interrupt-controller
> + - '#interrupt-cells'
> + - aspeed,interrupt-ranges
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> + interrupt-controller@12100000 {
> + compatible = "aspeed,ast2700-intc0";
> + reg = <0x12100000 0x3b00>;
> + interrupt-parent = <&gic>;
> + interrupt-controller;
> + #interrupt-cells = <1>;
> +
> + aspeed,interrupt-ranges =
> + <0 128 &gic GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
> + <144 8 &gic GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
> + <152 8 &gic GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>,
> + <192 10 &gic GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>,
> + <208 10 &gic GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>,
> + <224 10 &gic GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>,
> + <256 128 &ssp_nvic 0 0>,
> + <384 10 &ssp_nvic 160 0>,
> + <400 8 &ssp_nvic 144 0>,
> + <408 8 &ssp_nvic 152 0>,
> + <426 128 &tsp_nvic 0 0>,
> + <554 10 &tsp_nvic 160 0>,
> + <570 8 &tsp_nvic 144 0>,
> + <578 8 &tsp_nvic 152 0>;
> + };
>
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* RE: [PATCH v2 1/5] dt-bindings: interrupt-controller: aspeed: Add AST2700-A2 support
2026-03-23 19:07 ` Rob Herring
@ 2026-03-24 2:24 ` Ryan Chen
0 siblings, 0 replies; 9+ messages in thread
From: Ryan Chen @ 2026-03-24 2:24 UTC (permalink / raw)
To: Rob Herring
Cc: Krzysztof Kozlowski, Conor Dooley, Joel Stanley, Andrew Jeffery,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Thomas Gleixner, linux-kernel@vger.kernel.org,
devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-aspeed@lists.ozlabs.org, linux-riscv@lists.infradead.org
Hello Rob,
Thanks the review.
> Subject: Re: [PATCH v2 1/5] dt-bindings: interrupt-controller: aspeed: Add
> AST2700-A2 support
>
> On Fri, Mar 06, 2026 at 04:07:23PM +0800, Ryan Chen wrote:
> > Introduce a new binding describing the AST2700 interrupt controller
> > architecture implemented in the A2 production silicon.
> >
> > The AST2700 SoC has undergone multiple silicon revisions (A0, A1, A2)
> > prior to mass production. The interrupt architecture was substantially
> > reworked after the A0 revision for A1, and the A1 design is retained
> > unchanged in the A2 production silicon.
> >
> > The existing AST2700 interrupt controller binding was written against
> > the pre-production A0 design. That binding does not accurately
> > describe the interrupt hierarchy and routing model present in A1/A2,
> > where interrupts can be routed to multiple processor-local interrupt
> > controllers (Primary Service Processor (PSP) GIC, Secondary Service
> > Processor (SSP)/Tertiary Service Processor (TSP) NVICs, and BootMCU
> > APLIC) depending on the execution context.
>
> Unless you intend to maintain both bindings for some period, then you should
> just squash the removal here. If both are going to be maintained then patch 5
> should not be applied yet.
I will remove 5/5 squash to 1/5.
>
> >
> > Hardware connectivity between interrupt controllers is expressed using
> > the aspeed,interrupt-ranges property.
> >
> > Signed-off-by: Ryan Chen <ryan_chen@aspeedtech.com>
> >
> > ---
> > Changes in v2:
> > - Describe AST2700 A0/A1/A2 design evolution.
> > - Drop the redundant '-ic' suffix from compatible strings.
> > - Expand commit message to match the series cover letter context.
> > - fix ascii diagram
> > - remove intc0 label
> > - remove spaces before >
> > - drop intc1 example
> > ---
> > .../aspeed,ast2700-interrupt.yaml | 189
> +++++++++++++++++++++
> > 1 file changed, 189 insertions(+)
> >
> > diff --git
> > a/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast270
> > 0-interrupt.yaml
> > b/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast270
> > 0-interrupt.yaml
> > new file mode 100644
> > index 000000000000..13398ff8be12
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/interrupt-controller/aspeed,as
> > +++ t2700-interrupt.yaml
> > @@ -0,0 +1,189 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
> > +---
> > +$id:
> > +http://devicetree.org/schemas/interrupt-controller/aspeed,ast2700-int
> > +errupt.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: ASPEED AST2700 Interrupt Controllers (INTC0/INTC1)
> > +
> > +description: |
> > + The ASPEED AST2700 SoC integrates two interrupt controller designs:
> > +
> > + - INTC0: Primary controller that routes interrupt sources to upstream,
> > + processor-specific interrupt controllers
> > +
> > + - INTC1: Secondary controller whose interrupt outputs feed into
> > + INTC0
>
> Wrap lines at 80 char.
Will update
>
> > +
> > + The SoC contains four processors to which interrupts can be routed:
> > +
> > + - PSP: Primary Service Processor (Cortex-A35)
> > + - SSP: Secondary Service Processor (Cortex-M4)
> > + - TSP: Tertiary Sevice Processor (Cortex-M4)
> > + - BMCU: Boot MCU (a RISC-V microcontroller)
> > +
> > + The following diagram illustrates the overall architecture of the
> > + ASPEED AST2700 interrupt controllers:
> > +
> > + +-----------+ +-----------+
> > + | INTC0 | | INTC1(0) |
> > + +-----------+ +-----------+
> > + | Router | +-----------+ | Router |
> > + | out int | +Peripheral + | out int |
> > + +-----------+ | 0 0 <-+Controllers+ | INTM |
> +-----------+
> > + |PSP GIC <-|---+ . . | +-----------+ | . . <-+Peripheral
> +
> > + +-----------+ | . . | | . . |
> +Controllers+
> > + +-----------+ | . . | | . . |
> +-----------+
> > + |SSP NVIC <-|---+ . . <----------------+ . . |
> > + +-----------+ | . . | | . . |
> > + +-----------+ | . . <-------- | . . |
> > + |TSP NVIC <-|---+ . . | | ----+ . . |
> > + +-----------+ | . . | | | | O P |
> > + | . . | | | +-----------+
> > + | . . <---- | --------------------
> > + | . . | | | +-----------+ |
> > + | M N | | ---------+ INTC1(1) | |
> > + +-----------+ | +-----------+ |
> > + | .
> |
> > + | +-----------+ |
> > + -------------+ INTC1(N) | |
> > + +-----------+ |
> > + +--------------+ |
> > + + BMCU APLIC <-+---------------------------------------------
> > + +--------------+
> > +
> > + INTC0 supports:
> > + - 128 local peripheral interrupt inputs
> > + - Fan-in from up to three INTC1 instances via banked interrupt lines
> (INTM)
> > + - Local peripheral interrupt outputs
> > + - Merged interrupt outputs
> > + - Software interrupt outputs (SWINT)
> > + - Configurable interrupt routes targeting the PSP, SSP, and TSP
> > +
> > + INTC1 supports:
> > + - 192 local peripheral interrupt inputs
> > + - Banked interrupt outputs (INTM, 5 x 6 banks x 32 interrupts per bank)
> > + - Configurable interrupt routes targeting the PSP, SSP, TSP, and
> > + BMCU
> > +
> > + One INTC1 instance is always present, on the SoC's IO die. A
> > + further two instances may be attached to the SoC's one INTC0
> > + instance via LTPI (LVDS Tunneling Protocol & Interface).
> > +
> > + Interrupt numbering model
> > + -------------------------
> > + The binding uses a controller-local numbering model. Peripheral
> > + device nodes use the INTCx local interrupt number (hwirq) in their
> > + 'interrupts' or 'interrupts-extended' properties.
> > +
> > + For AST2700, INTC0 exposes the following (inclusive) input ranges:
> > +
> > + - 000..479: Independent interrupts
> > + - 480..489: INTM0-INTM9
> > + - 490..499: INTM10-INTM19
> > + - 500..509: INTM20-INTM29
> > + - 510..519: INTM30-INTM39
> > + - 520..529: INTM40-INTM49
> > +
> > + INTC0's (inclusive) output ranges are as follows:
> > +
> > + - 000..127: 1:1 local peripheral interrupt output to PSP
> > + - 144..151: Software interrupts from the SSP output to PSP
> > + - 152..159: Software interrupts from the TSP output to PSP
> > + - 192..201: INTM0-INTM9 banked outputs to PSP
> > + - 208..217: INTM30-INTM39 banked outputs to PSP
> > + - 224..233: INTM40-INTM49 banked outputs to PSP
> > + - 256..383: 1:1 local peripheral interrupt output to SSP
> > + - 384..393: INTM10-INTM19 banked outputs to SSP
> > + - 400..407: Software interrupts from the PSP output to SSP
> > + - 408..415: Software interrupts from the TSP output to SSP
> > + - 426..553: 1:1 local peripheral interrupt output to TSP
> > + - 554..563: INTM20-INTM29 banked outputs to TSP
> > + - 570..577: Software interrupts from the PSP output to TSP
> > + - 578..585: Software interrupts from the SSP output to TSP
> > +
> > + Inputs and outputs for INTC1 instances are context-dependent.
> > + However, for the first instance of INTC1, the (inclusive) output ranges are:
> > +
> > + - 00..05: INTM0-INTM5
> > + - 10..15: INTM10-INTM15
> > + - 20..25: INTM20-INTM25
> > + - 30..35: INTM30-INTM35
> > + - 40..45: INTM40-INTM45
> > + - 50..50: BootMCU
> > +
> > +maintainers:
> > + - ryan_chen@aspeedtech.com
> > + - andrew@codeconstruct.com.au
>
> Name and email address please.
Will update.
>
> > +
> > +properties:
> > + compatible:
> > + enum:
> > + - aspeed,ast2700-intc0
> > + - aspeed,ast2700-intc1
> > +
> > + reg:
> > + maxItems: 1
> > +
> > + interrupt-controller: true
> > +
> > + '#interrupt-cells':
> > + const: 1
> > + description: Single cell encoding the INTC local interrupt number
> (hwirq).
> > +
> > + aspeed,interrupt-ranges:
> > + description: |
> > + Describes how ranges of controller output pins are routed to a
> parent
> > + interrupt controller.
> > +
> > + Each range entry is encoded as:
> > +
> > + <out count phandle parent-specifier...>
> > +
> > + where:
> > + - out: First controller interrupt output index in the range.
> > + - count: Number of consecutive controller interrupt outputs
> and parent
> > + interrupt inputs in this range.
> > + - phandle: Phandle to the parent interrupt controller node.
> > + - parent-specifier: Interrupt specifier, as defined by the parent
> > + interrupt controller binding.
> > + $ref: /schemas/types.yaml#/definitions/uint32-array
> > + minItems: 3
> > + items:
> > + description: Range descriptors with a parent interrupt specifier.
> > +
> > +required:
> > + - compatible
> > + - reg
> > + - interrupt-controller
> > + - '#interrupt-cells'
> > + - aspeed,interrupt-ranges
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > + - |
> > + #include <dt-bindings/interrupt-controller/arm-gic.h>
> > +
> > + interrupt-controller@12100000 {
> > + compatible = "aspeed,ast2700-intc0";
> > + reg = <0x12100000 0x3b00>;
> > + interrupt-parent = <&gic>;
> > + interrupt-controller;
> > + #interrupt-cells = <1>;
> > +
> > + aspeed,interrupt-ranges =
> > + <0 128 &gic GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
> > + <144 8 &gic GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
> > + <152 8 &gic GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>,
> > + <192 10 &gic GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>,
> > + <208 10 &gic GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>,
> > + <224 10 &gic GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>,
> > + <256 128 &ssp_nvic 0 0>,
> > + <384 10 &ssp_nvic 160 0>,
> > + <400 8 &ssp_nvic 144 0>,
> > + <408 8 &ssp_nvic 152 0>,
> > + <426 128 &tsp_nvic 0 0>,
> > + <554 10 &tsp_nvic 160 0>,
> > + <570 8 &tsp_nvic 144 0>,
> > + <578 8 &tsp_nvic 152 0>;
> > + };
> >
> > --
> > 2.34.1
> >
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-03-24 2:24 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-06 8:07 [PATCH v2 0/5] AST2700-A2 interrupt controller hierarchy and route support Ryan Chen
2026-03-06 8:07 ` [PATCH v2 1/5] dt-bindings: interrupt-controller: aspeed: Add AST2700-A2 support Ryan Chen
2026-03-20 8:24 ` Thomas Gleixner
2026-03-23 19:07 ` Rob Herring
2026-03-24 2:24 ` Ryan Chen
2026-03-06 8:07 ` [PATCH v2 2/5] irqchip/ast2700-intc: " Ryan Chen
2026-03-06 8:07 ` [PATCH v2 3/5] irqchip/ast2700-intc: Add KUnit tests for route resolution Ryan Chen
2026-03-06 8:07 ` [PATCH v2 4/5] irqchip/aspeed-intc: Remove AST2700-A0 support Ryan Chen
2026-03-06 8:07 ` [PATCH v2 5/5] dt-bindings: interrupt-controller: aspeed: " Ryan Chen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox