* Re: [PATCH RFC 7/9] arm64: dts: qcom: shikra-cqm-evk: Enable ethernet0
From: Mohd Ayaan Anwar @ 2026-06-15 3:55 UTC (permalink / raw)
To: Andrew Lunn
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Richard Cochran, Bjorn Andersson, Konrad Dybcio, Maxime Coquelin,
Alexandre Torgue, Russell King, linux-arm-msm, netdev, devicetree,
linux-kernel, linux-stm32, linux-arm-kernel
In-Reply-To: <6fde35ce-52dd-4679-9952-728b6553b843@lunn.ch>
On Thu, Jun 11, 2026 at 10:58:39PM +0200, Andrew Lunn wrote:
> > + ethphy0: ethernet-phy@7 {
> > + compatible = "ethernet-phy-ieee802.3-c22";
> > + reg = <7>;
> > + reset-gpios = <&tlmm 135 GPIO_ACTIVE_LOW>;
> > + reset-assert-us = <10000>;
> > + reset-deassert-us = <50000>;
> > + ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
> > + ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
>
> Are these two needed? It should default to 2ns, since that is what the
> RGMII standard says the delay should be.
>
That is true, I will remove these in v2.
Ayaan
^ permalink raw reply
* Re: [PATCH RFC 3/9] net: stmmac: qcom-ethqos: fix RGMII_ID mode to use DLL bypass
From: Mohd Ayaan Anwar @ 2026-06-15 3:54 UTC (permalink / raw)
To: Andrew Lunn
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Richard Cochran, Bjorn Andersson, Konrad Dybcio, Maxime Coquelin,
Alexandre Torgue, Russell King, linux-arm-msm, netdev, devicetree,
linux-kernel, linux-stm32, linux-arm-kernel
In-Reply-To: <42355330-c22a-4fce-98ab-dc22b321ff16@lunn.ch>
Hello Andrew,
On Thu, Jun 11, 2026 at 10:54:37PM +0200, Andrew Lunn wrote:
> On Fri, Jun 12, 2026 at 12:06:59AM +0530, Mohd Ayaan Anwar wrote:
> > When "rgmii-id" is selected the PHY supplies both TX and RX delays, so
> > the MAC must not add its own. The driver currently falls through to the
> > generic DLL initialisation path which programs it to add a delay.
> >
> > Power down the DLL and set DDR bypass mode for RGMII_ID, then program
> > the IO_MACRO via a new ethqos_rgmii_id_macro_init() helper. Also fix
> > ethqos_set_clk_tx_rate() to not double the clock rate in bypass mode at
> > 100M/10M, and remove RGMII_ID from the phase-shift suppression in
> > ethqos_rgmii_macro_init() since RGMII_ID no longer reaches that path.
>
> I'm curious how this works at the moment? Do no boards make use of
> RGMII ID? Are all current boards broken?
Searching through the DTS, I found that we have two boards using "rgmii"
(qcs404-evb-4000.dts and sa8155-adp.dts) and another board using
"rgmii-txid" (sa8540p-ride.dts). No board which uses RGMII ID.
I don't think any of these boards have extra long wires which would add
PCB level delay. They are against the netdev definitions for "rgmii" and
"rgmii-txid".
But the first two boards should still be working fine since the current
driver programs the IO_MACRO to add the delay when operating in RGMII
mode. I am not sure about the last board. I went through the different
versions of the ETHQOS programming guide, and it should reliably support
either only MAC side Rx/Tx delay -or- bypass mode (no MAC side delay),
with each having different clock requirements.
Ayaan
^ permalink raw reply
* [PATCH 8/8] clk: clocking-wizard: Use dev_err_probe() when mapping registers
From: Shubhrajyoti Datta @ 2026-06-15 3:48 UTC (permalink / raw)
To: linux-clk, linux-kernel
Cc: git, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michal Simek,
Shubhrajyoti Datta, devicetree, linux-arm-kernel
In-Reply-To: <20260615034845.3320286-1-shubhrajyoti.datta@amd.com>
Align the devm_platform_ioremap_resource() error path with clk_in1 and
s_axi_aclk handling for consistent logging and deferred-probe behavior.
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---
drivers/clk/xilinx/clk-xlnx-clock-wizard.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
index fe73ee02b54e..381e396aef0e 100644
--- a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
+++ b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
@@ -1277,7 +1277,8 @@ static int clk_wzrd_probe(struct platform_device *pdev)
clk_wzrd->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(clk_wzrd->base))
- return PTR_ERR(clk_wzrd->base);
+ return dev_err_probe(&pdev->dev, PTR_ERR(clk_wzrd->base),
+ "failed to map registers\n");
ret = of_property_read_u32(np, "xlnx,speed-grade", &clk_wzrd->speed_grade);
if (!ret) {
--
2.49.1
^ permalink raw reply related
* [PATCH 7/8] clk: clocking-wizard: Skip s_axi_aclk for static-config
From: Shubhrajyoti Datta @ 2026-06-15 3:48 UTC (permalink / raw)
To: linux-clk, linux-kernel
Cc: git, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michal Simek,
Shubhrajyoti Datta, devicetree, linux-arm-kernel
In-Reply-To: <20260615034845.3320286-1-shubhrajyoti.datta@amd.com>
For static-config mode the AXI bus interface is not used, so there is
no need to get and enable s_axi_aclk. Move the axi_clk setup inside
the non-static-config branch.
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---
drivers/clk/xilinx/clk-xlnx-clock-wizard.c | 23 +++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
index 5470a717fccc..fe73ee02b54e 100644
--- a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
+++ b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
@@ -1243,7 +1243,6 @@ static int clk_wzrd_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct clk_wzrd *clk_wzrd;
const char *clk_name;
- unsigned long rate;
struct clk_hw *hw;
int nr_outputs;
int ret, i;
@@ -1258,22 +1257,24 @@ static int clk_wzrd_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, clk_wzrd);
- clk_wzrd->axi_clk = devm_clk_get_enabled(&pdev->dev, "s_axi_aclk");
- if (IS_ERR(clk_wzrd->axi_clk))
- return dev_err_probe(&pdev->dev, PTR_ERR(clk_wzrd->axi_clk),
- "s_axi_aclk not found\n");
- rate = clk_get_rate(clk_wzrd->axi_clk);
- if (rate > WZRD_ACLK_MAX_FREQ) {
- dev_err(&pdev->dev, "s_axi_aclk frequency (%lu) too high\n", rate);
- return -EINVAL;
- }
-
clk_wzrd->clk_in1 = devm_clk_get(&pdev->dev, "clk_in1");
if (IS_ERR(clk_wzrd->clk_in1))
return dev_err_probe(&pdev->dev, PTR_ERR(clk_wzrd->clk_in1),
"failed to get clk_in1\n");
if (!of_property_present(np, "xlnx,static-config")) {
+ unsigned long rate;
+
+ clk_wzrd->axi_clk = devm_clk_get_enabled(&pdev->dev, "s_axi_aclk");
+ if (IS_ERR(clk_wzrd->axi_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(clk_wzrd->axi_clk),
+ "s_axi_aclk not found\n");
+ rate = clk_get_rate(clk_wzrd->axi_clk);
+ if (rate > WZRD_ACLK_MAX_FREQ) {
+ dev_err(&pdev->dev, "s_axi_aclk frequency (%lu) too high\n", rate);
+ return -EINVAL;
+ }
+
clk_wzrd->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(clk_wzrd->base))
return PTR_ERR(clk_wzrd->base);
--
2.49.1
^ permalink raw reply related
* [PATCH 6/8] clk: clocking-wizard: Add static-config clock provider support
From: Shubhrajyoti Datta @ 2026-06-15 3:48 UTC (permalink / raw)
To: linux-clk, linux-kernel
Cc: git, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michal Simek,
Shubhrajyoti Datta, devicetree, linux-arm-kernel
In-Reply-To: <20260615034845.3320286-1-shubhrajyoti.datta@amd.com>
When xlnx,static-config is present the divider/multiplier path is
synthesized inside the Wizard without exposing runtime MMIO
reconfiguration, so omit the AXI register mapping and advertise each
routed output clock as a clk_fixed_factor child of clk_in1 using the
synthesized ratios exported through xlnx,clk-mul-div.
However the parent clock of clk_in1 can still be gated, disabled, or
(re-)enabled after FPGA programming (typical FPGA Manager flows,
CCF-managed parents, PLL fabric power sequencing).
Add a 10 us delay in each output clock's .enable() hook so consumers
wait for reference settling before first access.
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---
drivers/clk/xilinx/clk-xlnx-clock-wizard.c | 137 ++++++++++++++++++++-
1 file changed, 136 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
index ffc78c90bee6..5470a717fccc 100644
--- a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
+++ b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
@@ -12,6 +12,7 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/of.h>
@@ -107,6 +108,7 @@
#define VER_WZRD_O_MAX 511
#define WZRD_MIN_ERR 20000
#define WZRD_FRAC_POINTS 1000
+#define WZRD_ENABLE_DELAY_US 10
/* Get the mask from width */
#define div_mask(width) ((1 << (width)) - 1)
@@ -697,6 +699,13 @@ static int clk_wzrd_ver_determine_rate_all(struct clk_hw *hw,
return 0;
}
+static int clk_wzrd_enable(struct clk_hw *hw)
+{
+ /* Allow the output clock to settle after enable */
+ udelay(WZRD_ENABLE_DELAY_US);
+ return 0;
+}
+
static const struct clk_ops clk_wzrd_ver_divider_ops = {
.determine_rate = clk_wzrd_determine_rate,
.set_rate = clk_wzrd_ver_dynamic_reconfig,
@@ -790,6 +799,85 @@ static const struct clk_ops clk_wzrd_clk_divider_ops_f = {
.recalc_rate = clk_wzrd_recalc_ratef,
};
+static unsigned long
+clk_wzrd_static_factor_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
+ unsigned long long rate;
+
+ rate = (unsigned long long)parent_rate * fix->mult;
+ do_div(rate, fix->div);
+ return (unsigned long)rate;
+}
+
+static int clk_wzrd_static_factor_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
+
+ if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
+ unsigned long best_parent;
+
+ best_parent = (req->rate / fix->mult) * fix->div;
+ req->best_parent_rate =
+ clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
+ }
+
+ req->rate = (req->best_parent_rate / fix->div) * fix->mult;
+
+ return 0;
+}
+
+static int clk_wzrd_static_factor_set_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ return 0;
+}
+
+static const struct clk_ops clk_wzrd_static_fixed_factor_ops = {
+ .enable = clk_wzrd_enable,
+ .determine_rate = clk_wzrd_static_factor_determine_rate,
+ .set_rate = clk_wzrd_static_factor_set_rate,
+ .recalc_rate = clk_wzrd_static_factor_recalc_rate,
+};
+
+static struct clk_hw *
+clk_wzrd_devm_register_static_fixed_factor(struct device *dev,
+ const char *name,
+ const struct clk_parent_data *parent_data,
+ unsigned long flags,
+ unsigned int mult,
+ unsigned int div)
+{
+ struct clk_init_data init = {};
+ struct clk_fixed_factor *fix;
+ struct clk_hw *hw;
+ int ret;
+
+ fix = devm_kzalloc(dev, sizeof(*fix), GFP_KERNEL);
+ if (!fix)
+ return ERR_PTR(-ENOMEM);
+
+ fix->mult = mult;
+ fix->div = div;
+
+ init.name = name;
+ init.ops = &clk_wzrd_static_fixed_factor_ops;
+ init.flags = flags;
+ init.parent_data = parent_data;
+ init.num_parents = 1;
+
+ fix->hw.init = &init;
+
+ hw = &fix->hw;
+ ret = devm_clk_hw_register(dev, hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return hw;
+}
+
static struct clk_hw *clk_wzrd_register_divf(struct device *dev,
const char *name,
const char *parent_name,
@@ -1154,9 +1242,11 @@ static int clk_wzrd_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct clk_wzrd *clk_wzrd;
+ const char *clk_name;
unsigned long rate;
+ struct clk_hw *hw;
int nr_outputs;
- int ret;
+ int ret, i;
ret = of_property_read_u32(np, "xlnx,nr-outputs", &nr_outputs);
if (ret || nr_outputs > WZRD_NUM_OUTPUTS)
@@ -1224,6 +1314,51 @@ static int clk_wzrd_probe(struct platform_device *pdev)
dev_warn(&pdev->dev,
"unable to register clock notifier\n");
}
+ } else {
+ u32 mul_div[WZRD_NUM_OUTPUTS * 2];
+ const struct clk_parent_data parent_data = { .fw_name = "clk_in1" };
+ int num_elems = nr_outputs * 2;
+
+ /*
+ * xlnx,clk-mul-div is a uint32-matrix of <mul div> pairs;
+ * FDT encodes it as a flat u32 array so we can read it directly.
+ */
+ ret = of_property_read_u32_array(np, "xlnx,clk-mul-div",
+ mul_div, num_elems);
+ if (ret) {
+ dev_err(&pdev->dev, "xlnx,clk-mul-div missing or invalid\n");
+ return ret;
+ }
+
+ for (i = 0; i < nr_outputs; i++) {
+ u32 mul = mul_div[2 * i];
+ u32 div = mul_div[2 * i + 1];
+
+ if (!mul || !div)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "invalid mul/div for clkout%d\n", i);
+
+ clk_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+ "%s_out%d", dev_name(&pdev->dev), i);
+ if (!clk_name)
+ return -ENOMEM;
+
+ hw = clk_wzrd_devm_register_static_fixed_factor(&pdev->dev, clk_name,
+ &parent_data,
+ CLK_SET_RATE_PARENT,
+ mul, div);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ clk_wzrd->clk_data.hws[i] = hw;
+ }
+
+ clk_wzrd->clk_data.num = nr_outputs;
+
+ ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get,
+ &clk_wzrd->clk_data);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "unable to register clock provider\n");
}
return 0;
--
2.49.1
^ permalink raw reply related
* [PATCH 4/8] clk: clocking-wizard: Do not map the memory for static-config
From: Shubhrajyoti Datta @ 2026-06-15 3:48 UTC (permalink / raw)
To: linux-clk, linux-kernel
Cc: git, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michal Simek,
Shubhrajyoti Datta, devicetree, linux-arm-kernel
In-Reply-To: <20260615034845.3320286-1-shubhrajyoti.datta@amd.com>
With xlnx,static-config the MMCM/PLL topology is fixed at synthesis time
and no register programming is performed; only the dynamic path needs
the AXI register block. Move devm_platform_ioremap_resource() under the
non-static-config branch.
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---
drivers/clk/xilinx/clk-xlnx-clock-wizard.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
index 4a0136349f71..e082051221be 100644
--- a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
+++ b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
@@ -1168,10 +1168,6 @@ static int clk_wzrd_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, clk_wzrd);
- clk_wzrd->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(clk_wzrd->base))
- return PTR_ERR(clk_wzrd->base);
-
clk_wzrd->axi_clk = devm_clk_get_enabled(&pdev->dev, "s_axi_aclk");
if (IS_ERR(clk_wzrd->axi_clk))
return dev_err_probe(&pdev->dev, PTR_ERR(clk_wzrd->axi_clk),
@@ -1183,6 +1179,10 @@ static int clk_wzrd_probe(struct platform_device *pdev)
}
if (!of_property_present(np, "xlnx,static-config")) {
+ clk_wzrd->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(clk_wzrd->base))
+ return PTR_ERR(clk_wzrd->base);
+
ret = of_property_read_u32(np, "xlnx,speed-grade", &clk_wzrd->speed_grade);
if (!ret) {
if (clk_wzrd->speed_grade < 1 || clk_wzrd->speed_grade > 3) {
--
2.49.1
^ permalink raw reply related
* [PATCH 5/8] clk: clocking-wizard: Move clk_in1 acquisition before static-config check
From: Shubhrajyoti Datta @ 2026-06-15 3:48 UTC (permalink / raw)
To: linux-clk, linux-kernel
Cc: git, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michal Simek,
Shubhrajyoti Datta, devicetree, linux-arm-kernel
In-Reply-To: <20260615034845.3320286-1-shubhrajyoti.datta@amd.com>
The clk_in1 is the input clock for both the dynamic reconfig and the
static-config paths. Acquire clk_in1 for static-config as well. Output
clocks are registered as fixed-factor children of clk_in1.
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---
drivers/clk/xilinx/clk-xlnx-clock-wizard.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
index e082051221be..ffc78c90bee6 100644
--- a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
+++ b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
@@ -1178,6 +1178,11 @@ static int clk_wzrd_probe(struct platform_device *pdev)
return -EINVAL;
}
+ clk_wzrd->clk_in1 = devm_clk_get(&pdev->dev, "clk_in1");
+ if (IS_ERR(clk_wzrd->clk_in1))
+ return dev_err_probe(&pdev->dev, PTR_ERR(clk_wzrd->clk_in1),
+ "failed to get clk_in1\n");
+
if (!of_property_present(np, "xlnx,static-config")) {
clk_wzrd->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(clk_wzrd->base))
@@ -1192,11 +1197,6 @@ static int clk_wzrd_probe(struct platform_device *pdev)
}
}
- clk_wzrd->clk_in1 = devm_clk_get(&pdev->dev, "clk_in1");
- if (IS_ERR(clk_wzrd->clk_in1))
- return dev_err_probe(&pdev->dev, PTR_ERR(clk_wzrd->clk_in1),
- "clk_in1 not found\n");
-
ret = clk_wzrd_register_output_clocks(&pdev->dev, nr_outputs);
if (ret)
return ret;
--
2.49.1
^ permalink raw reply related
* [PATCH 3/8] dt-bindings: clock: clocking-wizard: Make s_axi_aclk optional for static-config
From: Shubhrajyoti Datta @ 2026-06-15 3:48 UTC (permalink / raw)
To: linux-clk, linux-kernel
Cc: git, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michal Simek,
Shubhrajyoti Datta, devicetree, linux-arm-kernel
In-Reply-To: <20260615034845.3320286-1-shubhrajyoti.datta@amd.com>
In static-config mode the AXI bus interface is unused, so s_axi_aclk
is not required. Allow clocks/clock-names to have only one entry
(clk_in1) when xlnx,static-config is present and enforce two entries
otherwise. Update the static-config example accordingly.
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---
.../bindings/clock/xlnx,clocking-wizard.yaml | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml b/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml
index aa397550d107..0daefe89ea89 100644
--- a/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml
+++ b/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml
@@ -29,11 +29,13 @@ properties:
const: 1
clocks:
+ minItems: 1
items:
- description: clock input
- description: axi clock
clock-names:
+ minItems: 1
items:
- const: clk_in1
- const: s_axi_aclk
@@ -87,9 +89,19 @@ allOf:
then:
required:
- xlnx,clk-mul-div
+ properties:
+ clocks:
+ maxItems: 1
+ clock-names:
+ maxItems: 1
else:
required:
- reg
+ properties:
+ clocks:
+ minItems: 2
+ clock-names:
+ minItems: 2
additionalProperties: false
@@ -109,8 +121,8 @@ examples:
clock-controller {
compatible = "xlnx,clocking-wizard";
#clock-cells = <1>;
- clocks = <&clkc 15>, <&clkc 18>;
- clock-names = "clk_in1", "s_axi_aclk";
+ clocks = <&clkc 15>;
+ clock-names = "clk_in1";
xlnx,nr-outputs = <6>;
xlnx,speed-grade = <1>;
xlnx,static-config;
--
2.49.1
^ permalink raw reply related
* [PATCH 0/8] clk: clocking-wizard: Add static-config clock provider support
From: Shubhrajyoti Datta @ 2026-06-15 3:48 UTC (permalink / raw)
To: linux-clk, linux-kernel
Cc: git, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michal Simek,
Shubhrajyoti Datta, devicetree, linux-arm-kernel
The Xilinx clocking-wizard IP can be used in a static-config mode
where the hardware is pre-programmed at boot and no dynamic register
access is required. In that case the driver should skip ioremap,
read the fixed multiplier/divisor pairs from the device tree, and
register fixed-factor clocks derived from clk_in1.
Currently the xlnx,static-config is not functional as it doesnot
model the output clocks. The series fixes the same.
This series:
- adds the xlnx,clk-mul-div binding to carry mul/div pairs
- makes the reg property optional for static-config nodes
- skips ioremap when xlnx,static-config is present
- moves clk_in1 acquisition before the static-config check so it
is available in both code paths
- registers fixed-factor output clocks in static-config mode
Shubhrajyoti Datta (8):
dt-bindings: clock: clocking-wizard: Add xlnx,clk-mul-div property
dt-bindings: clock: clocking-wizard: Make reg optional for
static-config
dt-bindings: clock: clocking-wizard: Make s_axi_aclk optional for
static-config
clk: clocking-wizard: Do not map the memory for static-config
clk: clocking-wizard: Move clk_in1 acquisition before static-config
check
clk: clocking-wizard: Add static-config clock provider support
clk: clocking-wizard: Skip s_axi_aclk for static-config
clk: clocking-wizard: Use dev_err_probe() when mapping registers
.../bindings/clock/xlnx,clocking-wizard.yaml | 50 ++++-
drivers/clk/xilinx/clk-xlnx-clock-wizard.c | 181 ++++++++++++++++--
2 files changed, 205 insertions(+), 26 deletions(-)
--
2.34.1
^ permalink raw reply
* [PATCH 1/8] dt-bindings: clock: clocking-wizard: Add xlnx,clk-mul-div property
From: Shubhrajyoti Datta @ 2026-06-15 3:48 UTC (permalink / raw)
To: linux-clk, linux-kernel
Cc: git, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michal Simek,
Shubhrajyoti Datta, devicetree, linux-arm-kernel
In-Reply-To: <20260615034845.3320286-1-shubhrajyoti.datta@amd.com>
Static-config MMCM/PLL ratios are fixed at IP build time, so the kernel
cannot read per-output multiply/divide from registers and needs DT pairs
to register fixed-factor clocks. Also add the tuples by pair in example.
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---
.../bindings/clock/xlnx,clocking-wizard.yaml | 24 +++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml b/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml
index b497c28e8094..8316654b0a91 100644
--- a/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml
+++ b/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml
@@ -57,6 +57,21 @@ properties:
description:
Number of outputs.
+ xlnx,clk-mul-div:
+ $ref: /schemas/types.yaml#/definitions/uint32-matrix
+ description:
+ Fixed MMCM/PLL multiply/divide ratios, one (multiplier, divisor)
+ pair per clock output relative to clk_in1. The number of entries
+ must equal xlnx,nr-outputs.
+ minItems: 1
+ maxItems: 8
+ items:
+ items:
+ - description: multiplier
+ minimum: 1
+ - description: divisor
+ minimum: 1
+
required:
- compatible
- reg
@@ -66,6 +81,14 @@ required:
- xlnx,speed-grade
- xlnx,nr-outputs
+allOf:
+ - if:
+ required:
+ - xlnx,static-config
+ then:
+ required:
+ - xlnx,clk-mul-div
+
additionalProperties: false
examples:
@@ -77,6 +100,7 @@ examples:
xlnx,static-config;
xlnx,speed-grade = <1>;
xlnx,nr-outputs = <6>;
+ xlnx,clk-mul-div = <12 1>, <10 2>, <8 1>, <6 1>, <4 2>, <2 1>;
clock-names = "clk_in1", "s_axi_aclk";
clocks = <&clkc 15>, <&clkc 15>;
};
--
2.49.1
^ permalink raw reply related
* [PATCH 2/8] dt-bindings: clock: clocking-wizard: Make reg optional for static-config
From: Shubhrajyoti Datta @ 2026-06-15 3:48 UTC (permalink / raw)
To: linux-clk, linux-kernel
Cc: git, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michal Simek,
Shubhrajyoti Datta, devicetree, linux-arm-kernel
In-Reply-To: <20260615034845.3320286-1-shubhrajyoti.datta@amd.com>
In static-config mode the IP exposes only fixed-factor clock outputs and
has no runtime-programmable registers, so reg is not required.
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---
.../bindings/clock/xlnx,clocking-wizard.yaml | 22 ++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml b/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml
index 8316654b0a91..aa397550d107 100644
--- a/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml
+++ b/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml
@@ -74,7 +74,6 @@ properties:
required:
- compatible
- - reg
- "#clock-cells"
- clocks
- clock-names
@@ -88,20 +87,33 @@ allOf:
then:
required:
- xlnx,clk-mul-div
+ else:
+ required:
+ - reg
additionalProperties: false
examples:
- |
- clock-controller@b0000000 {
+ clock-controller@b0000000 {
compatible = "xlnx,clocking-wizard";
reg = <0xb0000000 0x10000>;
#clock-cells = <1>;
- xlnx,static-config;
+ clocks = <&clkc 15>, <&clkc 18>;
+ clock-names = "clk_in1", "s_axi_aclk";
+ xlnx,nr-outputs = <6>;
xlnx,speed-grade = <1>;
+ };
+
+ - |
+ clock-controller {
+ compatible = "xlnx,clocking-wizard";
+ #clock-cells = <1>;
+ clocks = <&clkc 15>, <&clkc 18>;
+ clock-names = "clk_in1", "s_axi_aclk";
xlnx,nr-outputs = <6>;
+ xlnx,speed-grade = <1>;
+ xlnx,static-config;
xlnx,clk-mul-div = <12 1>, <10 2>, <8 1>, <6 1>, <4 2>, <2 1>;
- clock-names = "clk_in1", "s_axi_aclk";
- clocks = <&clkc 15>, <&clkc 15>;
};
...
--
2.49.1
^ permalink raw reply related
* Re: [PATCH v3 05/11] of: reserved_mem: split alloc_reserved_mem_array() from fdt_scan_reserved_mem_late()
From: Wandun @ 2026-06-15 3:33 UTC (permalink / raw)
To: Rob Herring
Cc: linux-arm-kernel, linux-kernel, loongarch, linux-riscv,
devicetree, kexec, iommu, zhaomeijing, catalin.marinas, will,
chenhuacai, kernel, pjw, palmer, aou, alex, saravanak, akpm, bhe,
rppt, pasha.tatashin, pratyush, ruirui.yang, m.szyprowski,
robin.murphy, quic_obabatun
In-Reply-To: <20260612144122.GA974326-robh@kernel.org>
On 6/12/26 22:41, Rob Herring wrote:
> On Wed, May 27, 2026 at 11:29:11AM +0800, Wandun Chen wrote:
>> From: Wandun Chen <chenwandun@lixiang.com>
>>
>> Prepare for storing /memreserve/ entries in the reserved_mem array.
>> alloc_reserved_mem_array is skipped if the device tree lacks a
>> /reserved-memory node, pointer 'reserved_mem' continues to reference
>> the reserved_mem_array which lives in __initdata, storing
>> /memreserve/ entries into reserved_mem_array would result in metadata
>> loss, and an out-of-bounds memory access will occur if the device
>> tree contains more than MAX_RESERVED_REGIONS /memreserve/ entries.
>>
>> So split alloc_reserved_mem_array() from fdt_scan_reserved_mem_late(),
>> and call alloc_reserved_mem_array() whether or not there is a
>> /reserved-memory node.
>>
>> No functional change.
>> The actual /memreserve/ population is added in a follow-up patch.
>>
>> Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
>> ---
>> drivers/of/fdt.c | 7 +++++--
>> drivers/of/of_private.h | 1 +
>> drivers/of/of_reserved_mem.c | 6 +-----
>> 3 files changed, 7 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
>> index 82f7327c59ea..83a2a474831e 100644
>> --- a/drivers/of/fdt.c
>> +++ b/drivers/of/fdt.c
>> @@ -1284,8 +1284,11 @@ void __init unflatten_device_tree(void)
>> {
>> void *fdt = initial_boot_params;
>>
>> - /* Save the statically-placed regions in the reserved_mem array */
>> - fdt_scan_reserved_mem_late();
>> + /* Attempt dynamic allocation of a new reserved_mem array */
>> + if (fdt && alloc_reserved_mem_array()) {
>> + /* Save the statically-placed regions in the reserved_mem array */
>> + fdt_scan_reserved_mem_late();
>
> Can we make this just:
>
> alloc_reserved_mem_array();
> fdt_scan_reserved_mem_late();
>
> We already check !fdt in fdt_scan_reserved_mem_late().
Thanks for you review, Rob.
The reason I kept the fdt check is that total_reserved_mem_cnt is wrong
when fdt is NULL, early_init_fdt_scan_reserved_mem() returns early in
that case, so fdt_scan_reserved_mem() never runs, and
total_reserved_mem_cnt stays at MAX_RESERVED_REGIONS. Calling
alloc_reserved_mem_array() unconditionally would allocate unnecessarily
memory.
A better fix might be to make total_reserved_mem_cnt always correct, add
a !fdt check at the top of fdt_scan_reserved_mem() that sets
total_reserved_mem_cnt to 0, and let early_init_fdt_scan_reserved_mem()
call it even when initial_boot_params is NULL. Then
alloc_reserved_mem_array() could naturally skip allcation when that
count is 0, and we can drop the outer fdt guard.
There is still separate UAF issue (fixed in patch3) if we don't check
the return value of alloc_reserved_mem_array().
With the fdt_scan_reserved_mem() fix for total_reserved_mem_cnt, the
call site in unflatten_device_tree() becomes:
if (alloc_reserved_mem_array()) {
fdt_scan_reserved_mem_late();
}
How does that sound?
Best regards,
Wandun
>
> Rob
^ permalink raw reply
* [PATCH 3/6] irqchip/gic-v3-its: Fix its node leak in gic_acpi_parse_madt_its()
From: Kemeng Shi @ 2026-06-15 3:29 UTC (permalink / raw)
To: maz, tglx; +Cc: linux-arm-kernel, linux-kernel, shikemeng
In-Reply-To: <20260615032910.54735-1-shikemeng@huaweicloud.com>
Fix its node leak when its_probe_one() failed in
gic_acpi_parse_madt_its().
Signed-off-by: Kemeng Shi <shikemeng@huaweicloud.com>
---
drivers/irqchip/irq-gic-v3-its.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index df26ddc97ae2..158937c867fb 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -5750,9 +5750,13 @@ static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header,
its->flags |= ITS_FLAGS_FORCE_NON_SHAREABLE;
err = its_probe_one(its);
- if (!err)
- return 0;
+ if (err)
+ goto probe_err;
+
+ return 0;
+probe_err:
+ its_node_destroy(its);
node_err:
iort_deregister_domain_token(its_entry->translation_id);
dom_err:
--
2.36.1
^ permalink raw reply related
* [PATCH 6/6] irqchip/gic-v3-its: some minor cleanups
From: Kemeng Shi @ 2026-06-15 3:29 UTC (permalink / raw)
To: maz, tglx; +Cc: linux-arm-kernel, linux-kernel, shikemeng
In-Reply-To: <20260615032910.54735-1-shikemeng@huaweicloud.com>
1. Remove unneeded NULL check in itt_alloc_pool() as addr will always be
NULL when we reach here.
2. Correct indentation in cpumask_pick_least_loaded()
3. Remove unneeded updation of range node when it is to be deleted in
alloc_lpi_range().
4. Remove unneeded assignment to baser->psz which is already used
as input inits_setup_baser()
Signed-off-by: Kemeng Shi <shikemeng@huaweicloud.com>
---
drivers/irqchip/irq-gic-v3-its.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index fc32a1709f76..ef505575ba86 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -273,7 +273,7 @@ static void *itt_alloc_pool(int node, int size)
break;
gen_pool_add(itt_pool, (unsigned long)page_address(page), PAGE_SIZE, node);
- } while (!addr);
+ } while (true);
return (void *)addr;
}
@@ -1681,7 +1681,7 @@ static unsigned int cpumask_pick_least_loaded(struct irq_data *d,
int this_count = its_read_lpi_count(d, tmp);
if (this_count < count) {
cpu = tmp;
- count = this_count;
+ count = this_count;
}
}
@@ -2127,12 +2127,13 @@ static int alloc_lpi_range(u32 nr_lpis, u32 *base)
list_for_each_entry_safe(range, tmp, &lpi_range_list, entry) {
if (range->span >= nr_lpis) {
*base = range->base_id;
- range->base_id += nr_lpis;
- range->span -= nr_lpis;
- if (range->span == 0) {
+ if (range->span == nr_lpis) {
list_del(&range->entry);
kfree(range);
+ } else {
+ range->base_id += nr_lpis;
+ range->span -= nr_lpis;
}
err = 0;
@@ -2472,7 +2473,6 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser,
baser->order = order;
baser->base = base;
- baser->psz = psz;
tmp = indirect ? GITS_LVL1_ENTRY_SIZE : esz;
pr_info("ITS@%pa: allocated %d %s @%llx (%s, esz %d, psz %dK, shr %d)\n",
--
2.36.1
^ permalink raw reply related
* [PATCH 4/6] irqchip/gic-v3-its: Add ITS address info in more error logs
From: Kemeng Shi @ 2026-06-15 3:29 UTC (permalink / raw)
To: maz, tglx; +Cc: linux-arm-kernel, linux-kernel, shikemeng
In-Reply-To: <20260615032910.54735-1-shikemeng@huaweicloud.com>
We have a lot of logs containing ITS address info which is helpful to
distiguish which ITS occurs error. Just add ITS address info into more
exsiting error logs.
Signed-off-by: Kemeng Shi <shikemeng@huaweicloud.com>
---
drivers/irqchip/irq-gic-v3-its.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 158937c867fb..becd8dd51720 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -1120,7 +1120,7 @@ static struct its_cmd_block *its_allocate_entry(struct its_node *its)
while (its_queue_full(its)) {
count--;
if (!count) {
- pr_err_ratelimited("ITS queue not draining\n");
+ pr_err_ratelimited("ITS@%pa queue not draining\n", &its->phys_base);
return NULL;
}
cpu_relax();
@@ -1196,8 +1196,8 @@ static int its_wait_for_range_completion(struct its_node *its,
count--;
if (!count) {
- pr_err_ratelimited("ITS queue timeout (%llu %llu)\n",
- to_idx, linear_idx);
+ pr_err_ratelimited("ITS@%pa queue timeout (%llu %llu)\n",
+ &its->phys_base, to_idx, linear_idx);
return -1;
}
prev_idx = rd_idx;
@@ -1244,7 +1244,7 @@ post: \
raw_spin_unlock_irqrestore(&its->lock, flags); \
\
if (its_wait_for_range_completion(its, rd_idx, next_cmd)) \
- pr_err_ratelimited("ITS cmd %ps failed\n", builder); \
+ pr_err_ratelimited("ITS@%pa cmd %ps failed\n", &its->phys_base, &builder); \
}
static void its_build_sync_cmd(struct its_node *its,
@@ -2408,7 +2408,8 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser,
/* 52bit PA is supported only when PageSize=64K */
if (psz != SZ_64K) {
- pr_err("ITS: no 52bit PA support when psz=%d\n", psz);
+ pr_err("ITS@%pa: no 52bit PA support when psz=%d\n",
+ &its->phys_base, psz);
its_free_pages(base, order);
return -ENXIO;
}
@@ -5184,7 +5185,7 @@ static int its_init_vpe_domain(void)
vpe_proxy.dev = its_create_device(its, devid, entries, false);
if (!vpe_proxy.dev) {
kfree(vpe_proxy.vpes);
- pr_err("ITS: Can't allocate GICv4 proxy device\n");
+ pr_err("ITS@%pa: Can't allocate GICv4 proxy device\n", &its->phys_base);
return -ENOMEM;
}
--
2.36.1
^ permalink raw reply related
* [PATCH 5/6] irqchip/gic-v3-its: fix typo in comments
From: Kemeng Shi @ 2026-06-15 3:29 UTC (permalink / raw)
To: maz, tglx; +Cc: linux-arm-kernel, linux-kernel, shikemeng
In-Reply-To: <20260615032910.54735-1-shikemeng@huaweicloud.com>
1. "If it some" -> "If some"
2. "by table by reading" -> by reading"
Signed-off-by: Kemeng Shi <shikemeng@huaweicloud.com>
---
drivers/irqchip/irq-gic-v3-its.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index becd8dd51720..fc32a1709f76 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -163,7 +163,7 @@ struct event_lpi_map {
/*
* The ITS view of a device - belongs to an ITS, owns an interrupt
- * translation table, and a list of interrupts. If it some of its
+ * translation table, and a list of interrupts. If some of its
* LPIs are injected into a guest (GICv4), the event_map.vm field
* indicates which one.
*/
@@ -2501,7 +2501,7 @@ static bool its_parse_indirect_baser(struct its_node *its,
if ((esz << ids) > (psz * 2)) {
/*
* Find out whether hw supports a single or two-level table by
- * table by reading bit at offset '62' after writing '1' to it.
+ * reading bit at offset '62' after writing '1' to it.
*/
its_write_baser(its, baser, val | GITS_BASER_INDIRECT);
indirect = !!(baser->val & GITS_BASER_INDIRECT);
--
2.36.1
^ permalink raw reply related
* [PATCH 2/6] irqchip/gic-v3-its: Fix memleak in its_probe_one()
From: Kemeng Shi @ 2026-06-15 3:29 UTC (permalink / raw)
To: maz, tglx; +Cc: linux-arm-kernel, linux-kernel, shikemeng
In-Reply-To: <20260615032910.54735-1-shikemeng@huaweicloud.com>
Fix collection leak when its_init_domain() failed in its_probe_one().
Signed-off-by: Kemeng Shi <shikemeng@huaweicloud.com>
---
drivers/irqchip/irq-gic-v3-its.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 2b7b546c43c8..df26ddc97ae2 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -3032,6 +3032,12 @@ static int its_alloc_collections(struct its_node *its)
return 0;
}
+static void its_free_collections(struct its_node *its)
+{
+ kfree(its->collections);
+ its->collections = NULL;
+}
+
static struct page *its_allocate_pending_table(gfp_t gfp_flags)
{
struct page *pend_page;
@@ -5323,7 +5329,7 @@ static int __init its_probe_one(struct its_node *its)
err = its_init_domain(its);
if (err)
- goto out_free_tables;
+ goto out_free_col;
raw_spin_lock(&its_lock);
list_add(&its->entry, &its_nodes);
@@ -5331,6 +5337,8 @@ static int __init its_probe_one(struct its_node *its)
return 0;
+out_free_col:
+ its_free_collections(its);
out_free_tables:
its_free_tables(its);
out_free_cmd:
--
2.36.1
^ permalink raw reply related
* [PATCH 1/6] irqchip/gic-v3-its: Fix LPI range leak and refactor error handler in its_lpi_alloc()
From: Kemeng Shi @ 2026-06-15 3:29 UTC (permalink / raw)
To: maz, tglx; +Cc: linux-arm-kernel, linux-kernel, shikemeng
In-Reply-To: <20260615032910.54735-1-shikemeng@huaweicloud.com>
Fix the LIP range leak when bitmap_zalloc() failed. Besides refactor
error handling code to make it a little simpler.
Signed-off-by: Kemeng Shi <shikemeng@huaweicloud.com>
---
drivers/irqchip/irq-gic-v3-its.c | 21 +++++++++------------
1 file changed, 9 insertions(+), 12 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 291d7668cc8d..2b7b546c43c8 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -2217,10 +2217,9 @@ static int __init its_lpi_init(u32 id_bits)
static unsigned long *its_lpi_alloc(int nr_irqs, u32 *base, int *nr_ids)
{
unsigned long *bitmap = NULL;
- int err = 0;
do {
- err = alloc_lpi_range(nr_irqs, base);
+ int err = alloc_lpi_range(nr_irqs, base);
if (!err)
break;
@@ -2228,22 +2227,20 @@ static unsigned long *its_lpi_alloc(int nr_irqs, u32 *base, int *nr_ids)
} while (nr_irqs > 0);
if (!nr_irqs)
- err = -ENOSPC;
-
- if (err)
- goto out;
+ goto err_out;
bitmap = bitmap_zalloc(nr_irqs, GFP_ATOMIC);
if (!bitmap)
- goto out;
+ goto err_free_lpi;
*nr_ids = nr_irqs;
-
-out:
- if (!bitmap)
- *base = *nr_ids = 0;
-
return bitmap;
+
+err_free_lpi:
+ free_lpi_range(*base, nr_irqs);
+err_out:
+ *base = *nr_ids = 0;
+ return NULL;
}
static void its_lpi_free(unsigned long *bitmap, u32 base, u32 nr_ids)
--
2.36.1
^ permalink raw reply related
* [PATCH v8 1/2] dt-bindings: arm: aspeed: add Meta ventura2 board
From: Kyle Hsieh @ 2026-06-15 2:46 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Joel Stanley,
Andrew Jeffery
Cc: devicetree, linux-arm-kernel, linux-aspeed, linux-kernel,
Kyle Hsieh, Krzysztof Kozlowski
In-Reply-To: <20260615-ventura2_initial_dts-v8-0-c89f92c80447@gmail.com>
Document the new compatibles used on Facebook ventura2.
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Kyle Hsieh <kylehsieh1995@gmail.com>
---
Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
index 9298c1a75dd1..d48607c86e8e 100644
--- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
+++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
@@ -92,6 +92,7 @@ properties:
- facebook,harma-bmc
- facebook,minerva-cmc
- facebook,santabarbara-bmc
+ - facebook,ventura2-rmc
- facebook,yosemite4-bmc
- facebook,yosemite5-bmc
- ibm,balcones-bmc
--
2.34.1
^ permalink raw reply related
* Re: [PATCH RFC 1/2] dt-bindings: pinctl: amlogic,pinctrl-a4: Add gpio irq property
From: Xianwei Zhao @ 2026-06-15 2:47 UTC (permalink / raw)
To: Conor Dooley
Cc: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Neil Armstrong, Kevin Hilman, Jerome Brunet, Martin Blumenstingl,
linux-amlogic, linux-gpio, devicetree, linux-kernel,
linux-arm-kernel
In-Reply-To: <20260611-ungloved-snowplow-522e7c0b7a51@spud>
Hi Conor,
Thanks for your review.
On 2026/6/12 01:39, Conor Dooley wrote:
> Subject:
> Re: [PATCH RFC 1/2] dt-bindings: pinctl: amlogic,pinctrl-a4: Add gpio
> irq property
> From:
> Conor Dooley <conor@kernel.org>
> Date:
> 2026/6/12 01:39
>
> To:
> xianwei.zhao@amlogic.com
> CC:
> Linus Walleij <linusw@kernel.org>, Rob Herring <robh@kernel.org>,
> Krzysztof Kozlowski <krzk+dt@kernel.org>, Conor Dooley
> <conor+dt@kernel.org>, Neil Armstrong <neil.armstrong@linaro.org>, Kevin
> Hilman <khilman@baylibre.com>, Jerome Brunet <jbrunet@baylibre.com>,
> Martin Blumenstingl <martin.blumenstingl@googlemail.com>,
> linux-amlogic@lists.infradead.org, linux-gpio@vger.kernel.org,
> devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
> linux-arm-kernel@lists.infradead.org
>
>
>
> On Thu, Jun 11, 2026 at 07:54:33AM +0000, Xianwei Zhao via B4 Relay wrote:
>> From: Xianwei Zhao<xianwei.zhao@amlogic.com>
>>
>> Add the hw-irq property for each GPIO bank and enable interrupt-parent
>> for pinctrl so that gpiod_to_irq() can translate GPIO lines to IRQs.
> Uhhhhh, what? Why can't you just use the normal interrupts property?
>
The interrupt cannot be used directly because the GPIO bank only
provides an IRQ base, which does not have a one-to-one mapping with the
actual hardware interrupts.
On Amlogic SoCs, GPIO interrupts are handled through a mux. Multiple
GPIO pins are mapped to a limited number of real interrupt sources. The
implementation can be found here:
https://github.com/torvalds/linux/blob/master/drivers/irqchip/irq-meson-gpio.c
To use a GPIO interrupt, an unused hardware interrupt must first be
allocated, and then the corresponding mux register must be configured.
This allocation and mapping are already implemented in the existing driver.
In that driver, the mapping is performed dynamically rather than simply
calculating:
irq = irq_start + gpio_offset
If the interrupt is used directly, only the GPIO index can be obtained.
The real interrupt number cannot be derived by simply adding an offset,
because the hardware interrupt must be allocated first. Pre-allocating
all interrupts during initialization would prevent later GPIOs from
obtaining available interrupt sources.
Perhaps other names would be more appropriate here, such as "irq_start".
>> Signed-off-by: Xianwei Zhao<xianwei.zhao@amlogic.com>
>> ---
>> Documentation/devicetree/bindings/pinctrl/amlogic,pinctrl-a4.yaml | 5 +++++
>> 1 file changed, 5 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/pinctrl/amlogic,pinctrl-a4.yaml b/Documentation/devicetree/bindings/pinctrl/amlogic,pinctrl-a4.yaml
>> index b69db1b95345..65ec9121300e 100644
>> --- a/Documentation/devicetree/bindings/pinctrl/amlogic,pinctrl-a4.yaml
>> +++ b/Documentation/devicetree/bindings/pinctrl/amlogic,pinctrl-a4.yaml
>> @@ -37,6 +37,8 @@ properties:
>>
>> ranges: true
>>
>> + interrupt-parent: true
>> +
>> patternProperties:
>> "^gpio@[0-9a-f]+$":
>> type: object
>> @@ -65,6 +67,9 @@ patternProperties:
>> gpio-ranges:
>> maxItems: 1
>>
>> + hw-irq:
>> + $ref: /schemas/types.yaml#/definitions/uint32
>> +
>> required:
>> - reg
>> - reg-names
>>
>> --
>> 2.52.0
^ permalink raw reply
* [PATCH v8 2/2] ARM: dts: aspeed: ventura2: Add Meta ventura2 BMC
From: Kyle Hsieh @ 2026-06-15 2:46 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Joel Stanley,
Andrew Jeffery
Cc: devicetree, linux-arm-kernel, linux-aspeed, linux-kernel,
Kyle Hsieh
In-Reply-To: <20260615-ventura2_initial_dts-v8-0-c89f92c80447@gmail.com>
Ventura2 is a Rack Management Controller. It is a modular
device designed to manage liquid cooling systems and monitor hardware
states within an IT rack. The system uses an AST2600 BMC for management.
RMCv2 serves several critical roles:
- Detects liquid leakage at both tray and rack levels.
- Communicates with and controls liquid cooling equipment.
- Manages leakage events and executes system recovery protocols.
Key hardware features include:
- An extensive I2C and IO expander topology to support comprehensive
sensor monitoring and backward compatibility with legacy trays.
- MCTP over I2C support for asynchronous device communications.
- A dual-flash design for BMC firmware redundancy.
Signed-off-by: Kyle Hsieh <kylehsieh1995@gmail.com>
---
arch/arm/boot/dts/aspeed/Makefile | 1 +
.../dts/aspeed/aspeed-bmc-facebook-ventura2.dts | 2903 ++++++++++++++++++++
2 files changed, 2904 insertions(+)
diff --git a/arch/arm/boot/dts/aspeed/Makefile b/arch/arm/boot/dts/aspeed/Makefile
index 9adf9278dc94..6b96997629d4 100644
--- a/arch/arm/boot/dts/aspeed/Makefile
+++ b/arch/arm/boot/dts/aspeed/Makefile
@@ -32,6 +32,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
aspeed-bmc-facebook-minipack.dtb \
aspeed-bmc-facebook-santabarbara.dtb \
aspeed-bmc-facebook-tiogapass.dtb \
+ aspeed-bmc-facebook-ventura2.dtb \
aspeed-bmc-facebook-wedge40.dtb \
aspeed-bmc-facebook-wedge100.dtb \
aspeed-bmc-facebook-wedge400-data64.dtb \
diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dts
new file mode 100644
index 000000000000..c64726bb0450
--- /dev/null
+++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-ventura2.dts
@@ -0,0 +1,2903 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2023 Facebook Inc.
+/dts-v1/;
+
+#include "aspeed-g6.dtsi"
+#include <dt-bindings/i2c/i2c.h>
+#include <dt-bindings/gpio/aspeed-gpio.h>
+
+/ {
+ model = "Facebook Ventura2 RMC";
+ compatible = "facebook,ventura2-rmc", "aspeed,ast2600";
+ aliases {
+ serial2 = &uart3;
+ serial4 = &uart5;
+
+ /*
+ * Pre-allocate I2C bus aliases for userspace predictability.
+ * Several I2C channels are intentionally left empty in this DTS
+ * as they are strictly reserved for future hardware feature expansions
+ * and add-on boards that will interface with these busses.
+ */
+ /*
+ * i2c switch 0-0077, pca9548, 8 child channels assigned
+ * with bus number 16-23.
+ */
+ i2c16 = &i2c0mux0ch0;
+ i2c17 = &i2c0mux0ch1;
+ i2c18 = &i2c0mux0ch2;
+ i2c19 = &i2c0mux0ch3;
+ i2c20 = &i2c0mux0ch4;
+ i2c21 = &i2c0mux0ch5;
+ i2c22 = &i2c0mux0ch6;
+ i2c23 = &i2c0mux0ch7;
+
+ /*
+ * i2c switch 1-0077, pca9548, 8 child channels assigned
+ * with bus number 24-31.
+ */
+ i2c24 = &i2c1mux0ch0;
+ i2c25 = &i2c1mux0ch1;
+ i2c26 = &i2c1mux0ch2;
+ i2c27 = &i2c1mux0ch3;
+ i2c28 = &i2c1mux0ch4;
+ i2c29 = &i2c1mux0ch5;
+ i2c30 = &i2c1mux0ch6;
+ i2c31 = &i2c1mux0ch7;
+
+ /*
+ * i2c switch 4-0077, pca9548, 8 child channels assigned
+ * with bus number 32-39.
+ */
+ i2c32 = &i2c4mux0ch0;
+ i2c33 = &i2c4mux0ch1;
+ i2c34 = &i2c4mux0ch2;
+ i2c35 = &i2c4mux0ch3;
+ i2c36 = &i2c4mux0ch4;
+ i2c37 = &i2c4mux0ch5;
+ i2c38 = &i2c4mux0ch6;
+ i2c39 = &i2c4mux0ch7;
+
+ /*
+ * i2c switch 5-0077, pca9548, 8 child channels assigned
+ * with bus number 40-47.
+ */
+ i2c40 = &i2c5mux0ch0;
+ i2c41 = &i2c5mux0ch1;
+ i2c42 = &i2c5mux0ch2;
+ i2c43 = &i2c5mux0ch3;
+ i2c44 = &i2c5mux0ch4;
+ i2c45 = &i2c5mux0ch5;
+ i2c46 = &i2c5mux0ch6;
+ i2c47 = &i2c5mux0ch7;
+
+ /*
+ * i2c switch 8-0077, pca9548, 8 child channels assigned
+ * with bus number 48-55.
+ */
+ i2c48 = &i2c8mux0ch0;
+ i2c49 = &i2c8mux0ch1;
+ i2c50 = &i2c8mux0ch2;
+ i2c51 = &i2c8mux0ch3;
+ i2c52 = &i2c8mux0ch4;
+ i2c53 = &i2c8mux0ch5;
+ i2c54 = &i2c8mux0ch6;
+ i2c55 = &i2c8mux0ch7;
+
+ /*
+ * i2c switch 11-0077, pca9548, 8 child channels assigned
+ * with bus number 56-63.
+ */
+ i2c56 = &i2c11mux0ch0;
+ i2c57 = &i2c11mux0ch1;
+ i2c58 = &i2c11mux0ch2;
+ i2c59 = &i2c11mux0ch3;
+ i2c60 = &i2c11mux0ch4;
+ i2c61 = &i2c11mux0ch5;
+ i2c62 = &i2c11mux0ch6;
+ i2c63 = &i2c11mux0ch7;
+
+ /*
+ * i2c switch 13-0077, pca9548, 8 child channels assigned
+ * with bus number 64-71.
+ */
+ i2c64 = &i2c13mux0ch0;
+ i2c65 = &i2c13mux0ch1;
+ i2c66 = &i2c13mux0ch2;
+ i2c67 = &i2c13mux0ch3;
+ i2c68 = &i2c13mux0ch4;
+ i2c69 = &i2c13mux0ch5;
+ i2c70 = &i2c13mux0ch6;
+ i2c71 = &i2c13mux0ch7;
+
+ /*
+ * i2c switch 15-0077, pca9548, 8 child channels assigned
+ * with bus number 72-79.
+ */
+ i2c72 = &i2c15mux0ch0;
+ i2c73 = &i2c15mux0ch1;
+ i2c74 = &i2c15mux0ch2;
+ i2c75 = &i2c15mux0ch3;
+ i2c76 = &i2c15mux0ch4;
+ i2c77 = &i2c15mux0ch5;
+ i2c78 = &i2c15mux0ch6;
+ i2c79 = &i2c15mux0ch7;
+ };
+
+ chosen {
+ stdout-path = "serial4:57600n8";
+ };
+
+ fan_leds {
+ compatible = "gpio-leds";
+
+ led-0 {
+ /* The 'ledd' intentionally matches the hardware schematic */
+ label = "fcb0fan0_ledd1_blue";
+ default-state = "off";
+ gpios = <&fan_io_expander0 0 GPIO_ACTIVE_LOW>;
+ };
+
+ led-1 {
+ label = "fcb0fan1_ledd2_blue";
+ default-state = "off";
+ gpios = <&fan_io_expander0 1 GPIO_ACTIVE_LOW>;
+ };
+
+ led-2 {
+ label = "fcb0fan2_ledd3_blue";
+ default-state = "off";
+ gpios = <&fan_io_expander1 0 GPIO_ACTIVE_LOW>;
+ };
+
+ led-3 {
+ label = "fcb0fan3_ledd4_blue";
+ default-state = "off";
+ gpios = <&fan_io_expander1 1 GPIO_ACTIVE_LOW>;
+ };
+
+ led-4 {
+ label = "fcb0fan0_ledd1_amber";
+ default-state = "off";
+ gpios = <&fan_io_expander0 4 GPIO_ACTIVE_LOW>;
+ };
+
+ led-5 {
+ label = "fcb0fan1_ledd2_amber";
+ default-state = "off";
+ gpios = <&fan_io_expander0 5 GPIO_ACTIVE_LOW>;
+ };
+
+ led-6 {
+ label = "fcb0fan2_ledd3_amber";
+ default-state = "off";
+ gpios = <&fan_io_expander1 4 GPIO_ACTIVE_LOW>;
+ };
+
+ led-7 {
+ label = "fcb0fan3_ledd4_amber";
+ default-state = "off";
+ gpios = <&fan_io_expander1 5 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ iio-hwmon {
+ compatible = "iio-hwmon";
+ io-channels = <&adc0 0>, <&adc0 1>, <&adc0 2>, <&adc0 3>,
+ <&adc0 4>, <&adc0 5>, <&adc0 6>, <&adc0 7>,
+ <&adc1 2>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led-0 {
+ label = "bmc_heartbeat_amber";
+ gpios = <&gpio0 ASPEED_GPIO(P, 7) GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "heartbeat";
+ };
+
+ led-1 {
+ label = "fp_id_amber";
+ default-state = "off";
+ gpios = <&gpio0 ASPEED_GPIO(B, 5) GPIO_ACTIVE_HIGH>;
+ };
+
+ led-2 {
+ label = "bmc_ready_noled";
+ default-state = "on";
+ gpios = <&gpio0 ASPEED_GPIO(B, 3) (GPIO_ACTIVE_HIGH|GPIO_TRANSITORY)>;
+ };
+
+ led-3 {
+ label = "power_blue";
+ default-state = "off";
+ gpios = <&gpio0 ASPEED_GPIO(P, 4) GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x80000000 0x80000000>;
+ };
+
+ p1v8_bmc_aux: regulator-p1v8-bmc-aux {
+ compatible = "regulator-fixed";
+ regulator-name = "p1v8_bmc_aux";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ p2v5_bmc_aux: regulator-p2v5-bmc-aux {
+ compatible = "regulator-fixed";
+ regulator-name = "p2v5_bmc_aux";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ regulator-always-on;
+ };
+
+ p5v_dac_aux: regulator-p5v-bmc-aux {
+ compatible = "regulator-fixed";
+ regulator-name = "p5v_dac_aux";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
+
+ spi1_gpio: spi {
+ compatible = "spi-gpio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sck-gpios = <&gpio0 ASPEED_GPIO(Z, 3) GPIO_ACTIVE_HIGH>;
+ mosi-gpios = <&gpio0 ASPEED_GPIO(Z, 4) GPIO_ACTIVE_HIGH>;
+ miso-gpios = <&gpio0 ASPEED_GPIO(Z, 5) GPIO_ACTIVE_HIGH>;
+ cs-gpios = <&gpio0 ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>;
+ num-chipselects = <1>;
+
+ tpm@0 {
+ compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
+ spi-max-frequency = <33000000>;
+ reg = <0>;
+ };
+ };
+};
+
+&adc0 {
+ vref-supply = <&p1v8_bmc_aux>;
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_adc0_default &pinctrl_adc1_default
+ &pinctrl_adc2_default &pinctrl_adc3_default
+ &pinctrl_adc4_default &pinctrl_adc5_default
+ &pinctrl_adc6_default &pinctrl_adc7_default>;
+};
+
+&adc1 {
+ vref-supply = <&p2v5_bmc_aux>;
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_adc8_default &pinctrl_adc10_default>;
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&fmc {
+ status = "okay";
+
+ flash@0 {
+ status = "okay";
+ m25p,fast-read;
+ label = "bmc";
+ spi-max-frequency = <50000000>;
+ #include "openbmc-flash-layout-128.dtsi"
+ };
+
+ flash@1 {
+ status = "okay";
+ m25p,fast-read;
+ label = "alt-bmc";
+ spi-max-frequency = <50000000>;
+ };
+};
+
+&gpio0 {
+ gpio-line-names =
+ /*A0-A7*/ "","","","","","","","",
+ /*B0-B7*/ "BATTERY_DETECT","","","BMC_READY_R",
+ "","FM_ID_LED","","",
+ /*C0-C7*/ "","","","","","","","",
+ /*D0-D7*/ "","","","","","","","",
+ /*E0-E7*/ "","","","","","","","",
+ /*F0-F7*/ "","","","","","","","",
+ /*G0-G7*/ "FM_MUX1_SEL_R","","","",
+ "","","","",
+ /*H0-H7*/ "","","","","","","","",
+ /*I0-I7*/ "","","","","","","","",
+ /*J0-J7*/ "","","","","","","","",
+ /*K0-K7*/ "","","","","","","","",
+ /*L0-L7*/ "","","","","","","","",
+ /*M0-M7*/ "","","","","STBY_POWER_PG_3V3","","","",
+ /*N0-N7*/ "LED_POSTCODE_0","LED_POSTCODE_1",
+ "LED_POSTCODE_2","LED_POSTCODE_3",
+ "LED_POSTCODE_4","LED_POSTCODE_5",
+ "LED_POSTCODE_6","LED_POSTCODE_7",
+ /*O0-O7*/ "","","","","","","","debug-card-mux",
+ /*P0-P7*/ "PWR_BTN_BMC_BUF_N","","ID_RST_BTN_BMC_N","",
+ "PWR_LED","","","BMC_HEARTBEAT_N",
+ /*Q0-Q7*/ "","","","","","","","",
+ /*R0-R7*/ "","","","","","","","",
+ /*S0-S7*/ "","","SYS_BMC_PWRBTN_R_N","","","","","",
+ /*T0-T7*/ "","","","","","","","",
+ /*U0-U7*/ "","","","","","","","",
+ /*V0-V7*/ "","","","","","","","",
+ /*W0-W7*/ "","","","","","","","",
+ /*X0-X7*/ "","","","","","","","",
+ /*Y0-Y7*/ "","","","","","","","",
+ /*Z0-Z7*/ "","","","","","","","";
+};
+
+&gpio1 {
+ gpio-line-names =
+ /*18A0-18A7*/ "","","","","","","","",
+ /*18B0-18B7*/ "","","","",
+ "FM_BOARD_BMC_REV_ID0","FM_BOARD_BMC_REV_ID1",
+ "FM_BOARD_BMC_REV_ID2","",
+ /*18C0-18C7*/ "SPI_BMC_BIOS_ROM_IRQ0_R_N","","","","","","","",
+ /*18D0-18D7*/ "","","","","","","","",
+ /*18E0-18E3*/ "FM_BMC_PROT_LS_EN","AC_PWR_BMC_BTN_R_N","","";
+};
+
+&i2c0 {
+ status = "okay";
+
+ i2c-mux@77 {
+ compatible = "nxp,pca9548";
+ reg = <0x77>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ i2c-mux-idle-disconnect;
+
+ i2c0mux0ch0: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ };
+
+ i2c0mux0ch1: i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ };
+
+ i2c0mux0ch2: i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ };
+
+ i2c0mux0ch3: i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ status = "okay";
+ };
+
+ i2c0mux0ch4: i2c@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+ status = "okay";
+ };
+
+ i2c0mux0ch5: i2c@5 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <5>;
+ status = "okay";
+
+ eeprom@56 {
+ compatible = "atmel,24c128";
+ reg = <0x56>;
+ };
+ };
+
+ i2c0mux0ch6: i2c@6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6>;
+
+ eeprom@56 {
+ compatible = "atmel,24c128";
+ reg = <0x56>;
+ };
+
+ fan_io_expander0: gpio@20 {
+ compatible = "nxp,pca9555";
+ reg = <0x20>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ fan_io_expander1: gpio@21 {
+ compatible = "nxp,pca9555";
+ reg = <0x21>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ adc@1d {
+ compatible = "ti,adc128d818";
+ reg = <0x1d>;
+ ti,mode = /bits/ 8 <1>;
+ };
+
+ adc@35 {
+ compatible = "maxim,max11617";
+ reg = <0x35>;
+ };
+ };
+
+ i2c0mux0ch7: i2c@7 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <7>;
+
+ fanctl0: fan-controller@20 {
+ compatible = "maxim,max31790";
+ reg = <0x20>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ channel@2 {
+ reg = <2>;
+ sensor-type = "TACH";
+ };
+
+ channel@5 {
+ reg = <5>;
+ sensor-type = "TACH";
+ };
+ };
+
+ fanctl1: fan-controller@23 {
+ compatible = "nuvoton,nct7363";
+ reg = <0x23>;
+ #pwm-cells = <2>;
+
+ fan-0 {
+ pwms = <&fanctl1 10 20000>;
+ tach-ch = /bits/ 8 <0x00>;
+ };
+
+ fan-1 {
+ pwms = <&fanctl1 6 20000>;
+ tach-ch = /bits/ 8 <0x01>;
+ };
+
+ fan-3 {
+ pwms = <&fanctl1 10 20000>;
+ tach-ch = /bits/ 8 <0x03>;
+ };
+
+ fan-9 {
+ pwms = <&fanctl1 0 20000>;
+ tach-ch = /bits/ 8 <0x09>;
+ };
+
+ fan-10 {
+ pwms = <&fanctl1 4 20000>;
+ tach-ch = /bits/ 8 <0x0A>;
+ };
+
+ fan-11 {
+ pwms = <&fanctl1 0 20000>;
+ tach-ch = /bits/ 8 <0x0B>;
+ };
+
+ fan-13 {
+ pwms = <&fanctl1 4 20000>;
+ tach-ch = /bits/ 8 <0x0D>;
+ };
+
+ fan-15 {
+ pwms = <&fanctl1 6 20000>;
+ tach-ch = /bits/ 8 <0x0F>;
+ };
+ };
+ };
+ };
+};
+
+&i2c1 {
+ status = "okay";
+
+ i2c-mux@77 {
+ compatible = "nxp,pca9548";
+ reg = <0x77>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ i2c-mux-idle-disconnect;
+
+ i2c1mux0ch0: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ status = "okay";
+ };
+
+ i2c1mux0ch1: i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ status = "okay";
+ };
+
+ i2c1mux0ch2: i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ status = "okay";
+ };
+
+ i2c1mux0ch3: i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ status = "okay";
+ };
+
+ i2c1mux0ch4: i2c@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+ status = "okay";
+ };
+
+ i2c1mux0ch5: i2c@5 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <5>;
+ status = "okay";
+ };
+
+ i2c1mux0ch6: i2c@6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6>;
+ status = "okay";
+ };
+
+ i2c1mux0ch7: i2c@7 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <7>;
+ status = "okay";
+ };
+ };
+};
+
+&i2c2 {
+ status = "okay";
+ bus-frequency = <400000>;
+};
+
+&i2c3 {
+ status = "okay";
+ bus-frequency = <400000>;
+
+ dac@c {
+ reg = <0x0c>;
+ compatible = "adi,ad5612";
+ vcc-supply = <&p5v_dac_aux>;
+ };
+
+ dac@e {
+ reg = <0x0e>;
+ compatible = "adi,ad5612";
+ vcc-supply = <&p5v_dac_aux>;
+ };
+
+ dac@f {
+ reg = <0x0f>;
+ compatible = "adi,ad5612";
+ vcc-supply = <&p5v_dac_aux>;
+ };
+
+ io_expander6: gpio@23 {
+ compatible = "nxp,pca9555";
+ reg = <0x23>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&io_expander7>;
+ interrupts = <6 IRQ_TYPE_LEVEL_LOW>;
+ };
+
+ prsnt_io_expander0: gpio@40 {
+ compatible = "nxp,pca9698";
+ reg = <0x40>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <48 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN1_TRAY1_PRSNT", "CAN1_TRAY2_PRSNT",
+ "CAN1_TRAY3_PRSNT", "CAN1_TRAY4_PRSNT",
+ "CAN1_TRAY5_PRSNT", "CAN1_TRAY6_PRSNT",
+ "CAN1_TRAY7_PRSNT", "CAN1_TRAY8_PRSNT",
+ "CAN1_TRAY9_PRSNT", "CAN1_TRAY10_PRSNT",
+ "CAN1_TRAY11_PRSNT", "CAN1_TRAY12_PRSNT",
+ "CAN1_TRAY13_PRSNT", "CAN1_TRAY14_PRSNT",
+ "CAN1_TRAY15_PRSNT", "CAN1_TRAY16_PRSNT",
+ "CAN1_TRAY17_PRSNT", "CAN1_TRAY18_PRSNT",
+ "CAN1_TRAY19_PRSNT", "CAN1_TRAY20_PRSNT",
+ "CAN1_TRAY21_PRSNT", "CAN1_TRAY22_PRSNT",
+ "CAN1_TRAY23_PRSNT", "CAN1_TRAY24_PRSNT",
+ "CAN1_TRAY25_PRSNT", "CAN1_TRAY26_PRSNT",
+ "CAN1_TRAY27_PRSNT", "CAN1_TRAY28_PRSNT",
+ "CAN1_TRAY29_PRSNT", "CAN1_TRAY30_PRSNT",
+ "CAN1_TRAY31_PRSNT", "CAN1_TRAY32_PRSNT",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ prsnt_io_expander1: gpio@41 {
+ compatible = "nxp,pca9698";
+ reg = <0x41>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <56 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN2_TRAY1_PRSNT", "CAN2_TRAY2_PRSNT",
+ "CAN2_TRAY3_PRSNT", "CAN2_TRAY4_PRSNT",
+ "CAN2_TRAY5_PRSNT", "CAN2_TRAY6_PRSNT",
+ "CAN2_TRAY7_PRSNT", "CAN2_TRAY8_PRSNT",
+ "CAN2_TRAY9_PRSNT", "CAN2_TRAY10_PRSNT",
+ "CAN2_TRAY11_PRSNT", "CAN2_TRAY12_PRSNT",
+ "CAN2_TRAY13_PRSNT", "CAN2_TRAY14_PRSNT",
+ "CAN2_TRAY15_PRSNT", "CAN2_TRAY16_PRSNT",
+ "CAN2_TRAY17_PRSNT", "CAN2_TRAY18_PRSNT",
+ "CAN2_TRAY19_PRSNT", "CAN2_TRAY20_PRSNT",
+ "CAN2_TRAY21_PRSNT", "CAN2_TRAY22_PRSNT",
+ "CAN2_TRAY23_PRSNT", "CAN2_TRAY24_PRSNT",
+ "CAN2_TRAY25_PRSNT", "CAN2_TRAY26_PRSNT",
+ "CAN2_TRAY27_PRSNT", "CAN2_TRAY28_PRSNT",
+ "CAN2_TRAY29_PRSNT", "CAN2_TRAY30_PRSNT",
+ "CAN2_TRAY31_PRSNT", "CAN2_TRAY32_PRSNT",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ prsnt_io_expander2: gpio@42 {
+ compatible = "nxp,pca9698";
+ reg = <0x42>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <64 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN3_TRAY1_PRSNT", "CAN3_TRAY2_PRSNT",
+ "CAN3_TRAY3_PRSNT", "CAN3_TRAY4_PRSNT",
+ "CAN3_TRAY5_PRSNT", "CAN3_TRAY6_PRSNT",
+ "CAN3_TRAY7_PRSNT", "CAN3_TRAY8_PRSNT",
+ "CAN3_TRAY9_PRSNT", "CAN3_TRAY10_PRSNT",
+ "CAN3_TRAY11_PRSNT", "CAN3_TRAY12_PRSNT",
+ "CAN3_TRAY13_PRSNT", "CAN3_TRAY14_PRSNT",
+ "CAN3_TRAY15_PRSNT", "CAN3_TRAY16_PRSNT",
+ "CAN3_TRAY17_PRSNT", "CAN3_TRAY18_PRSNT",
+ "CAN3_TRAY19_PRSNT", "CAN3_TRAY20_PRSNT",
+ "CAN3_TRAY21_PRSNT", "CAN3_TRAY22_PRSNT",
+ "CAN3_TRAY23_PRSNT", "CAN3_TRAY24_PRSNT",
+ "CAN3_TRAY25_PRSNT", "CAN3_TRAY26_PRSNT",
+ "CAN3_TRAY27_PRSNT", "CAN3_TRAY28_PRSNT",
+ "CAN3_TRAY29_PRSNT", "CAN3_TRAY30_PRSNT",
+ "CAN3_TRAY31_PRSNT", "CAN3_TRAY32_PRSNT",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ prsnt_io_expander3: gpio@43 {
+ compatible = "nxp,pca9698";
+ reg = <0x43>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <72 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN4_TRAY1_PRSNT", "CAN4_TRAY2_PRSNT",
+ "CAN4_TRAY3_PRSNT", "CAN4_TRAY4_PRSNT",
+ "CAN4_TRAY5_PRSNT", "CAN4_TRAY6_PRSNT",
+ "CAN4_TRAY7_PRSNT", "CAN4_TRAY8_PRSNT",
+ "CAN4_TRAY9_PRSNT", "CAN4_TRAY10_PRSNT",
+ "CAN4_TRAY11_PRSNT", "CAN4_TRAY12_PRSNT",
+ "CAN4_TRAY13_PRSNT", "CAN4_TRAY14_PRSNT",
+ "CAN4_TRAY15_PRSNT", "CAN4_TRAY16_PRSNT",
+ "CAN4_TRAY17_PRSNT", "CAN4_TRAY18_PRSNT",
+ "CAN4_TRAY19_PRSNT", "CAN4_TRAY20_PRSNT",
+ "CAN4_TRAY21_PRSNT", "CAN4_TRAY22_PRSNT",
+ "CAN4_TRAY23_PRSNT", "CAN4_TRAY24_PRSNT",
+ "CAN4_TRAY25_PRSNT", "CAN4_TRAY26_PRSNT",
+ "CAN4_TRAY27_PRSNT", "CAN4_TRAY28_PRSNT",
+ "CAN4_TRAY29_PRSNT", "CAN4_TRAY30_PRSNT",
+ "CAN4_TRAY31_PRSNT", "CAN4_TRAY32_PRSNT",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ prsnt_io_expander4: gpio@44 {
+ compatible = "nxp,pca9698";
+ reg = <0x44>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <80 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN5_TRAY1_PRSNT", "CAN5_TRAY2_PRSNT",
+ "CAN5_TRAY3_PRSNT", "CAN5_TRAY4_PRSNT",
+ "CAN5_TRAY5_PRSNT", "CAN5_TRAY6_PRSNT",
+ "CAN5_TRAY7_PRSNT", "CAN5_TRAY8_PRSNT",
+ "CAN5_TRAY9_PRSNT", "CAN5_TRAY10_PRSNT",
+ "CAN5_TRAY11_PRSNT", "CAN5_TRAY12_PRSNT",
+ "CAN5_TRAY13_PRSNT", "CAN5_TRAY14_PRSNT",
+ "CAN5_TRAY15_PRSNT", "CAN5_TRAY16_PRSNT",
+ "CAN5_TRAY17_PRSNT", "CAN5_TRAY18_PRSNT",
+ "CAN5_TRAY19_PRSNT", "CAN5_TRAY20_PRSNT",
+ "CAN5_TRAY21_PRSNT", "CAN5_TRAY22_PRSNT",
+ "CAN5_TRAY23_PRSNT", "CAN5_TRAY24_PRSNT",
+ "CAN5_TRAY25_PRSNT", "CAN5_TRAY26_PRSNT",
+ "CAN5_TRAY27_PRSNT", "CAN5_TRAY28_PRSNT",
+ "CAN5_TRAY29_PRSNT", "CAN5_TRAY30_PRSNT",
+ "CAN5_TRAY31_PRSNT", "CAN5_TRAY32_PRSNT",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ prsnt_io_expander5: gpio@45 {
+ compatible = "nxp,pca9698";
+ reg = <0x45>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <88 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN6_TRAY1_PRSNT", "CAN6_TRAY2_PRSNT",
+ "CAN6_TRAY3_PRSNT", "CAN6_TRAY4_PRSNT",
+ "CAN6_TRAY5_PRSNT", "CAN6_TRAY6_PRSNT",
+ "CAN6_TRAY7_PRSNT", "CAN6_TRAY8_PRSNT",
+ "CAN6_TRAY9_PRSNT", "CAN6_TRAY10_PRSNT",
+ "CAN6_TRAY11_PRSNT", "CAN6_TRAY12_PRSNT",
+ "CAN6_TRAY13_PRSNT", "CAN6_TRAY14_PRSNT",
+ "CAN6_TRAY15_PRSNT", "CAN6_TRAY16_PRSNT",
+ "CAN6_TRAY17_PRSNT", "CAN6_TRAY18_PRSNT",
+ "CAN6_TRAY19_PRSNT", "CAN6_TRAY20_PRSNT",
+ "CAN6_TRAY21_PRSNT", "CAN6_TRAY22_PRSNT",
+ "CAN6_TRAY23_PRSNT", "CAN6_TRAY24_PRSNT",
+ "CAN6_TRAY25_PRSNT", "CAN6_TRAY26_PRSNT",
+ "CAN6_TRAY27_PRSNT", "CAN6_TRAY28_PRSNT",
+ "CAN6_TRAY29_PRSNT", "CAN6_TRAY30_PRSNT",
+ "CAN6_TRAY31_PRSNT", "CAN6_TRAY32_PRSNT",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ prsnt_io_expander6: gpio@46 {
+ compatible = "nxp,pca9698";
+ reg = <0x46>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <96 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN7_TRAY1_PRSNT", "CAN7_TRAY2_PRSNT",
+ "CAN7_TRAY3_PRSNT", "CAN7_TRAY4_PRSNT",
+ "CAN7_TRAY5_PRSNT", "CAN7_TRAY6_PRSNT",
+ "CAN7_TRAY7_PRSNT", "CAN7_TRAY8_PRSNT",
+ "CAN7_TRAY9_PRSNT", "CAN7_TRAY10_PRSNT",
+ "CAN7_TRAY11_PRSNT", "CAN7_TRAY12_PRSNT",
+ "CAN7_TRAY13_PRSNT", "CAN7_TRAY14_PRSNT",
+ "CAN7_TRAY15_PRSNT", "CAN7_TRAY16_PRSNT",
+ "CAN7_TRAY17_PRSNT", "CAN7_TRAY18_PRSNT",
+ "CAN7_TRAY19_PRSNT", "CAN7_TRAY20_PRSNT",
+ "CAN7_TRAY21_PRSNT", "CAN7_TRAY22_PRSNT",
+ "CAN7_TRAY23_PRSNT", "CAN7_TRAY24_PRSNT",
+ "CAN7_TRAY25_PRSNT", "CAN7_TRAY26_PRSNT",
+ "CAN7_TRAY27_PRSNT", "CAN7_TRAY28_PRSNT",
+ "CAN7_TRAY29_PRSNT", "CAN7_TRAY30_PRSNT",
+ "CAN7_TRAY31_PRSNT", "CAN7_TRAY32_PRSNT",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ prsnt_io_expander7: gpio@47 {
+ compatible = "nxp,pca9698";
+ reg = <0x47>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <104 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN8_TRAY1_PRSNT", "CAN8_TRAY2_PRSNT",
+ "CAN8_TRAY3_PRSNT", "CAN8_TRAY4_PRSNT",
+ "CAN8_TRAY5_PRSNT", "CAN8_TRAY6_PRSNT",
+ "CAN8_TRAY7_PRSNT", "CAN8_TRAY8_PRSNT",
+ "CAN8_TRAY9_PRSNT", "CAN8_TRAY10_PRSNT",
+ "CAN8_TRAY11_PRSNT", "CAN8_TRAY12_PRSNT",
+ "CAN8_TRAY13_PRSNT", "CAN8_TRAY14_PRSNT",
+ "CAN8_TRAY15_PRSNT", "CAN8_TRAY16_PRSNT",
+ "CAN8_TRAY17_PRSNT", "CAN8_TRAY18_PRSNT",
+ "CAN8_TRAY19_PRSNT", "CAN8_TRAY20_PRSNT",
+ "CAN8_TRAY21_PRSNT", "CAN8_TRAY22_PRSNT",
+ "CAN8_TRAY23_PRSNT", "CAN8_TRAY24_PRSNT",
+ "CAN8_TRAY25_PRSNT", "CAN8_TRAY26_PRSNT",
+ "CAN8_TRAY27_PRSNT", "CAN8_TRAY28_PRSNT",
+ "CAN8_TRAY29_PRSNT", "CAN8_TRAY30_PRSNT",
+ "CAN8_TRAY31_PRSNT", "CAN8_TRAY32_PRSNT",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ pwrgd_io_expander0: gpio@48 {
+ compatible = "nxp,pca9698";
+ reg = <0x48>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <50 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN1_TRAY1_PWRGD", "CAN1_TRAY2_PWRGD",
+ "CAN1_TRAY3_PWRGD", "CAN1_TRAY4_PWRGD",
+ "CAN1_TRAY5_PWRGD", "CAN1_TRAY6_PWRGD",
+ "CAN1_TRAY7_PWRGD", "CAN1_TRAY8_PWRGD",
+ "CAN1_TRAY9_PWRGD", "CAN1_TRAY10_PWRGD",
+ "CAN1_TRAY11_PWRGD", "CAN1_TRAY12_PWRGD",
+ "CAN1_TRAY13_PWRGD", "CAN1_TRAY14_PWRGD",
+ "CAN1_TRAY15_PWRGD", "CAN1_TRAY16_PWRGD",
+ "CAN1_TRAY17_PWRGD", "CAN1_TRAY18_PWRGD",
+ "CAN1_TRAY19_PWRGD", "CAN1_TRAY20_PWRGD",
+ "CAN1_TRAY21_PWRGD", "CAN1_TRAY22_PWRGD",
+ "CAN1_TRAY23_PWRGD", "CAN1_TRAY24_PWRGD",
+ "CAN1_TRAY25_PWRGD", "CAN1_TRAY26_PWRGD",
+ "CAN1_TRAY27_PWRGD", "CAN1_TRAY28_PWRGD",
+ "CAN1_TRAY29_PWRGD", "CAN1_TRAY30_PWRGD",
+ "CAN1_TRAY31_PWRGD", "CAN1_TRAY32_PWRGD",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ pwrgd_io_expander1: gpio@49 {
+ compatible = "nxp,pca9698";
+ reg = <0x49>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <58 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN2_TRAY1_PWRGD", "CAN2_TRAY2_PWRGD",
+ "CAN2_TRAY3_PWRGD", "CAN2_TRAY4_PWRGD",
+ "CAN2_TRAY5_PWRGD", "CAN2_TRAY6_PWRGD",
+ "CAN2_TRAY7_PWRGD", "CAN2_TRAY8_PWRGD",
+ "CAN2_TRAY9_PWRGD", "CAN2_TRAY10_PWRGD",
+ "CAN2_TRAY11_PWRGD", "CAN2_TRAY12_PWRGD",
+ "CAN2_TRAY13_PWRGD", "CAN2_TRAY14_PWRGD",
+ "CAN2_TRAY15_PWRGD", "CAN2_TRAY16_PWRGD",
+ "CAN2_TRAY17_PWRGD", "CAN2_TRAY18_PWRGD",
+ "CAN2_TRAY19_PWRGD", "CAN2_TRAY20_PWRGD",
+ "CAN2_TRAY21_PWRGD", "CAN2_TRAY22_PWRGD",
+ "CAN2_TRAY23_PWRGD", "CAN2_TRAY24_PWRGD",
+ "CAN2_TRAY25_PWRGD", "CAN2_TRAY26_PWRGD",
+ "CAN2_TRAY27_PWRGD", "CAN2_TRAY28_PWRGD",
+ "CAN2_TRAY29_PWRGD", "CAN2_TRAY30_PWRGD",
+ "CAN2_TRAY31_PWRGD", "CAN2_TRAY32_PWRGD",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ pwrgd_io_expander2: gpio@4a {
+ compatible = "nxp,pca9698";
+ reg = <0x4a>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <66 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN3_TRAY1_PWRGD", "CAN3_TRAY2_PWRGD",
+ "CAN3_TRAY3_PWRGD", "CAN3_TRAY4_PWRGD",
+ "CAN3_TRAY5_PWRGD", "CAN3_TRAY6_PWRGD",
+ "CAN3_TRAY7_PWRGD", "CAN3_TRAY8_PWRGD",
+ "CAN3_TRAY9_PWRGD", "CAN3_TRAY10_PWRGD",
+ "CAN3_TRAY11_PWRGD", "CAN3_TRAY12_PWRGD",
+ "CAN3_TRAY13_PWRGD", "CAN3_TRAY14_PWRGD",
+ "CAN3_TRAY15_PWRGD", "CAN3_TRAY16_PWRGD",
+ "CAN3_TRAY17_PWRGD", "CAN3_TRAY18_PWRGD",
+ "CAN3_TRAY19_PWRGD", "CAN3_TRAY20_PWRGD",
+ "CAN3_TRAY21_PWRGD", "CAN3_TRAY22_PWRGD",
+ "CAN3_TRAY23_PWRGD", "CAN3_TRAY24_PWRGD",
+ "CAN3_TRAY25_PWRGD", "CAN3_TRAY26_PWRGD",
+ "CAN3_TRAY27_PWRGD", "CAN3_TRAY28_PWRGD",
+ "CAN3_TRAY29_PWRGD", "CAN3_TRAY30_PWRGD",
+ "CAN3_TRAY31_PWRGD", "CAN3_TRAY32_PWRGD",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ pwrgd_io_expander3: gpio@4b {
+ compatible = "nxp,pca9698";
+ reg = <0x4b>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <74 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN4_TRAY1_PWRGD", "CAN4_TRAY2_PWRGD",
+ "CAN4_TRAY3_PWRGD", "CAN4_TRAY4_PWRGD",
+ "CAN4_TRAY5_PWRGD", "CAN4_TRAY6_PWRGD",
+ "CAN4_TRAY7_PWRGD", "CAN4_TRAY8_PWRGD",
+ "CAN4_TRAY9_PWRGD", "CAN4_TRAY10_PWRGD",
+ "CAN4_TRAY11_PWRGD", "CAN4_TRAY12_PWRGD",
+ "CAN4_TRAY13_PWRGD", "CAN4_TRAY14_PWRGD",
+ "CAN4_TRAY15_PWRGD", "CAN4_TRAY16_PWRGD",
+ "CAN4_TRAY17_PWRGD", "CAN4_TRAY18_PWRGD",
+ "CAN4_TRAY19_PWRGD", "CAN4_TRAY20_PWRGD",
+ "CAN4_TRAY21_PWRGD", "CAN4_TRAY22_PWRGD",
+ "CAN4_TRAY23_PWRGD", "CAN4_TRAY24_PWRGD",
+ "CAN4_TRAY25_PWRGD", "CAN4_TRAY26_PWRGD",
+ "CAN4_TRAY27_PWRGD", "CAN4_TRAY28_PWRGD",
+ "CAN4_TRAY29_PWRGD", "CAN4_TRAY30_PWRGD",
+ "CAN4_TRAY31_PWRGD", "CAN4_TRAY32_PWRGD",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ pwrgd_io_expander4: gpio@4c {
+ compatible = "nxp,pca9698";
+ reg = <0x4c>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <82 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN5_TRAY1_PWRGD", "CAN5_TRAY2_PWRGD",
+ "CAN5_TRAY3_PWRGD", "CAN5_TRAY4_PWRGD",
+ "CAN5_TRAY5_PWRGD", "CAN5_TRAY6_PWRGD",
+ "CAN5_TRAY7_PWRGD", "CAN5_TRAY8_PWRGD",
+ "CAN5_TRAY9_PWRGD", "CAN5_TRAY10_PWRGD",
+ "CAN5_TRAY11_PWRGD", "CAN5_TRAY12_PWRGD",
+ "CAN5_TRAY13_PWRGD", "CAN5_TRAY14_PWRGD",
+ "CAN5_TRAY15_PWRGD", "CAN5_TRAY16_PWRGD",
+ "CAN5_TRAY17_PWRGD", "CAN5_TRAY18_PWRGD",
+ "CAN5_TRAY19_PWRGD", "CAN5_TRAY20_PWRGD",
+ "CAN5_TRAY21_PWRGD", "CAN5_TRAY22_PWRGD",
+ "CAN5_TRAY23_PWRGD", "CAN5_TRAY24_PWRGD",
+ "CAN5_TRAY25_PWRGD", "CAN5_TRAY26_PWRGD",
+ "CAN5_TRAY27_PWRGD", "CAN5_TRAY28_PWRGD",
+ "CAN5_TRAY29_PWRGD", "CAN5_TRAY30_PWRGD",
+ "CAN5_TRAY31_PWRGD", "CAN5_TRAY32_PWRGD",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ pwrgd_io_expander5: gpio@4d {
+ compatible = "nxp,pca9698";
+ reg = <0x4d>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <90 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN6_TRAY1_PWRGD", "CAN6_TRAY2_PWRGD",
+ "CAN6_TRAY3_PWRGD", "CAN6_TRAY4_PWRGD",
+ "CAN6_TRAY5_PWRGD", "CAN6_TRAY6_PWRGD",
+ "CAN6_TRAY7_PWRGD", "CAN6_TRAY8_PWRGD",
+ "CAN6_TRAY9_PWRGD", "CAN6_TRAY10_PWRGD",
+ "CAN6_TRAY11_PWRGD", "CAN6_TRAY12_PWRGD",
+ "CAN6_TRAY13_PWRGD", "CAN6_TRAY14_PWRGD",
+ "CAN6_TRAY15_PWRGD", "CAN6_TRAY16_PWRGD",
+ "CAN6_TRAY17_PWRGD", "CAN6_TRAY18_PWRGD",
+ "CAN6_TRAY19_PWRGD", "CAN6_TRAY20_PWRGD",
+ "CAN6_TRAY21_PWRGD", "CAN6_TRAY22_PWRGD",
+ "CAN6_TRAY23_PWRGD", "CAN6_TRAY24_PWRGD",
+ "CAN6_TRAY25_PWRGD", "CAN6_TRAY26_PWRGD",
+ "CAN6_TRAY27_PWRGD", "CAN6_TRAY28_PWRGD",
+ "CAN6_TRAY29_PWRGD", "CAN6_TRAY30_PWRGD",
+ "CAN6_TRAY31_PWRGD", "CAN6_TRAY32_PWRGD",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ pwrgd_io_expander6: gpio@4e {
+ compatible = "nxp,pca9698";
+ reg = <0x4e>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <98 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN7_TRAY1_PWRGD", "CAN7_TRAY2_PWRGD",
+ "CAN7_TRAY3_PWRGD", "CAN7_TRAY4_PWRGD",
+ "CAN7_TRAY5_PWRGD", "CAN7_TRAY6_PWRGD",
+ "CAN7_TRAY7_PWRGD", "CAN7_TRAY8_PWRGD",
+ "CAN7_TRAY9_PWRGD", "CAN7_TRAY10_PWRGD",
+ "CAN7_TRAY11_PWRGD", "CAN7_TRAY12_PWRGD",
+ "CAN7_TRAY13_PWRGD", "CAN7_TRAY14_PWRGD",
+ "CAN7_TRAY15_PWRGD", "CAN7_TRAY16_PWRGD",
+ "CAN7_TRAY17_PWRGD", "CAN7_TRAY18_PWRGD",
+ "CAN7_TRAY19_PWRGD", "CAN7_TRAY20_PWRGD",
+ "CAN7_TRAY21_PWRGD", "CAN7_TRAY22_PWRGD",
+ "CAN7_TRAY23_PWRGD", "CAN7_TRAY24_PWRGD",
+ "CAN7_TRAY25_PWRGD", "CAN7_TRAY26_PWRGD",
+ "CAN7_TRAY27_PWRGD", "CAN7_TRAY28_PWRGD",
+ "CAN7_TRAY29_PWRGD", "CAN7_TRAY30_PWRGD",
+ "CAN7_TRAY31_PWRGD", "CAN7_TRAY32_PWRGD",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ pwrgd_io_expander7: gpio@4f {
+ compatible = "nxp,pca9698";
+ reg = <0x4f>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <106 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN8_TRAY1_PWRGD", "CAN8_TRAY2_PWRGD",
+ "CAN8_TRAY3_PWRGD", "CAN8_TRAY4_PWRGD",
+ "CAN8_TRAY5_PWRGD", "CAN8_TRAY6_PWRGD",
+ "CAN8_TRAY7_PWRGD", "CAN8_TRAY8_PWRGD",
+ "CAN8_TRAY9_PWRGD", "CAN8_TRAY10_PWRGD",
+ "CAN8_TRAY11_PWRGD", "CAN8_TRAY12_PWRGD",
+ "CAN8_TRAY13_PWRGD", "CAN8_TRAY14_PWRGD",
+ "CAN8_TRAY15_PWRGD", "CAN8_TRAY16_PWRGD",
+ "CAN8_TRAY17_PWRGD", "CAN8_TRAY18_PWRGD",
+ "CAN8_TRAY19_PWRGD", "CAN8_TRAY20_PWRGD",
+ "CAN8_TRAY21_PWRGD", "CAN8_TRAY22_PWRGD",
+ "CAN8_TRAY23_PWRGD", "CAN8_TRAY24_PWRGD",
+ "CAN8_TRAY25_PWRGD", "CAN8_TRAY26_PWRGD",
+ "CAN8_TRAY27_PWRGD", "CAN8_TRAY28_PWRGD",
+ "CAN8_TRAY29_PWRGD", "CAN8_TRAY30_PWRGD",
+ "CAN8_TRAY31_PWRGD", "CAN8_TRAY32_PWRGD",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ large_leak_io_expander0: gpio@50 {
+ compatible = "nxp,pca9698";
+ reg = <0x50>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <54 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN1_TRAY1_LARGE_LEAK", "CAN1_TRAY2_LARGE_LEAK",
+ "CAN1_TRAY3_LARGE_LEAK", "CAN1_TRAY4_LARGE_LEAK",
+ "CAN1_TRAY5_LARGE_LEAK", "CAN1_TRAY6_LARGE_LEAK",
+ "CAN1_TRAY7_LARGE_LEAK", "CAN1_TRAY8_LARGE_LEAK",
+ "CAN1_TRAY9_LARGE_LEAK", "CAN1_TRAY10_LARGE_LEAK",
+ "CAN1_TRAY11_LARGE_LEAK", "CAN1_TRAY12_LARGE_LEAK",
+ "CAN1_TRAY13_LARGE_LEAK", "CAN1_TRAY14_LARGE_LEAK",
+ "CAN1_TRAY15_LARGE_LEAK", "CAN1_TRAY16_LARGE_LEAK",
+ "CAN1_TRAY17_LARGE_LEAK", "CAN1_TRAY18_LARGE_LEAK",
+ "CAN1_TRAY19_LARGE_LEAK", "CAN1_TRAY20_LARGE_LEAK",
+ "CAN1_TRAY21_LARGE_LEAK", "CAN1_TRAY22_LARGE_LEAK",
+ "CAN1_TRAY23_LARGE_LEAK", "CAN1_TRAY24_LARGE_LEAK",
+ "CAN1_TRAY25_LARGE_LEAK", "CAN1_TRAY26_LARGE_LEAK",
+ "CAN1_TRAY27_LARGE_LEAK", "CAN1_TRAY28_LARGE_LEAK",
+ "CAN1_TRAY29_LARGE_LEAK", "CAN1_TRAY30_LARGE_LEAK",
+ "CAN1_TRAY31_LARGE_LEAK", "CAN1_TRAY32_LARGE_LEAK",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ large_leak_io_expander1: gpio@51 {
+ compatible = "nxp,pca9698";
+ reg = <0x51>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <62 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN2_TRAY1_LARGE_LEAK", "CAN2_TRAY2_LARGE_LEAK",
+ "CAN2_TRAY3_LARGE_LEAK", "CAN2_TRAY4_LARGE_LEAK",
+ "CAN2_TRAY5_LARGE_LEAK", "CAN2_TRAY6_LARGE_LEAK",
+ "CAN2_TRAY7_LARGE_LEAK", "CAN2_TRAY8_LARGE_LEAK",
+ "CAN2_TRAY9_LARGE_LEAK", "CAN2_TRAY10_LARGE_LEAK",
+ "CAN2_TRAY11_LARGE_LEAK", "CAN2_TRAY12_LARGE_LEAK",
+ "CAN2_TRAY13_LARGE_LEAK", "CAN2_TRAY14_LARGE_LEAK",
+ "CAN2_TRAY15_LARGE_LEAK", "CAN2_TRAY16_LARGE_LEAK",
+ "CAN2_TRAY17_LARGE_LEAK", "CAN2_TRAY18_LARGE_LEAK",
+ "CAN2_TRAY19_LARGE_LEAK", "CAN2_TRAY20_LARGE_LEAK",
+ "CAN2_TRAY21_LARGE_LEAK", "CAN2_TRAY22_LARGE_LEAK",
+ "CAN2_TRAY23_LARGE_LEAK", "CAN2_TRAY24_LARGE_LEAK",
+ "CAN2_TRAY25_LARGE_LEAK", "CAN2_TRAY26_LARGE_LEAK",
+ "CAN2_TRAY27_LARGE_LEAK", "CAN2_TRAY28_LARGE_LEAK",
+ "CAN2_TRAY29_LARGE_LEAK", "CAN2_TRAY30_LARGE_LEAK",
+ "CAN2_TRAY31_LARGE_LEAK", "CAN2_TRAY32_LARGE_LEAK",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ large_leak_io_expander2: gpio@52 {
+ compatible = "nxp,pca9698";
+ reg = <0x52>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <70 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN3_TRAY1_LARGE_LEAK", "CAN3_TRAY2_LARGE_LEAK",
+ "CAN3_TRAY3_LARGE_LEAK", "CAN3_TRAY4_LARGE_LEAK",
+ "CAN3_TRAY5_LARGE_LEAK", "CAN3_TRAY6_LARGE_LEAK",
+ "CAN3_TRAY7_LARGE_LEAK", "CAN3_TRAY8_LARGE_LEAK",
+ "CAN3_TRAY9_LARGE_LEAK", "CAN3_TRAY10_LARGE_LEAK",
+ "CAN3_TRAY11_LARGE_LEAK", "CAN3_TRAY12_LARGE_LEAK",
+ "CAN3_TRAY13_LARGE_LEAK", "CAN3_TRAY14_LARGE_LEAK",
+ "CAN3_TRAY15_LARGE_LEAK", "CAN3_TRAY16_LARGE_LEAK",
+ "CAN3_TRAY17_LARGE_LEAK", "CAN3_TRAY18_LARGE_LEAK",
+ "CAN3_TRAY19_LARGE_LEAK", "CAN3_TRAY20_LARGE_LEAK",
+ "CAN3_TRAY21_LARGE_LEAK", "CAN3_TRAY22_LARGE_LEAK",
+ "CAN3_TRAY23_LARGE_LEAK", "CAN3_TRAY24_LARGE_LEAK",
+ "CAN3_TRAY25_LARGE_LEAK", "CAN3_TRAY26_LARGE_LEAK",
+ "CAN3_TRAY27_LARGE_LEAK", "CAN3_TRAY28_LARGE_LEAK",
+ "CAN3_TRAY29_LARGE_LEAK", "CAN3_TRAY30_LARGE_LEAK",
+ "CAN3_TRAY31_LARGE_LEAK", "CAN3_TRAY32_LARGE_LEAK",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ large_leak_io_expander3: gpio@53 {
+ compatible = "nxp,pca9698";
+ reg = <0x53>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <78 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN4_TRAY1_LARGE_LEAK", "CAN4_TRAY2_LARGE_LEAK",
+ "CAN4_TRAY3_LARGE_LEAK", "CAN4_TRAY4_LARGE_LEAK",
+ "CAN4_TRAY5_LARGE_LEAK", "CAN4_TRAY6_LARGE_LEAK",
+ "CAN4_TRAY7_LARGE_LEAK", "CAN4_TRAY8_LARGE_LEAK",
+ "CAN4_TRAY9_LARGE_LEAK", "CAN4_TRAY10_LARGE_LEAK",
+ "CAN4_TRAY11_LARGE_LEAK", "CAN4_TRAY12_LARGE_LEAK",
+ "CAN4_TRAY13_LARGE_LEAK", "CAN4_TRAY14_LARGE_LEAK",
+ "CAN4_TRAY15_LARGE_LEAK", "CAN4_TRAY16_LARGE_LEAK",
+ "CAN4_TRAY17_LARGE_LEAK", "CAN4_TRAY18_LARGE_LEAK",
+ "CAN4_TRAY19_LARGE_LEAK", "CAN4_TRAY20_LARGE_LEAK",
+ "CAN4_TRAY21_LARGE_LEAK", "CAN4_TRAY22_LARGE_LEAK",
+ "CAN4_TRAY23_LARGE_LEAK", "CAN4_TRAY24_LARGE_LEAK",
+ "CAN4_TRAY25_LARGE_LEAK", "CAN4_TRAY26_LARGE_LEAK",
+ "CAN4_TRAY27_LARGE_LEAK", "CAN4_TRAY28_LARGE_LEAK",
+ "CAN4_TRAY29_LARGE_LEAK", "CAN4_TRAY30_LARGE_LEAK",
+ "CAN4_TRAY31_LARGE_LEAK", "CAN4_TRAY32_LARGE_LEAK",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ large_leak_io_expander4: gpio@54 {
+ compatible = "nxp,pca9698";
+ reg = <0x54>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <86 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN5_TRAY1_LARGE_LEAK", "CAN5_TRAY2_LARGE_LEAK",
+ "CAN5_TRAY3_LARGE_LEAK", "CAN5_TRAY4_LARGE_LEAK",
+ "CAN5_TRAY5_LARGE_LEAK", "CAN5_TRAY6_LARGE_LEAK",
+ "CAN5_TRAY7_LARGE_LEAK", "CAN5_TRAY8_LARGE_LEAK",
+ "CAN5_TRAY9_LARGE_LEAK", "CAN5_TRAY10_LARGE_LEAK",
+ "CAN5_TRAY11_LARGE_LEAK", "CAN5_TRAY12_LARGE_LEAK",
+ "CAN5_TRAY13_LARGE_LEAK", "CAN5_TRAY14_LARGE_LEAK",
+ "CAN5_TRAY15_LARGE_LEAK", "CAN5_TRAY16_LARGE_LEAK",
+ "CAN5_TRAY17_LARGE_LEAK", "CAN5_TRAY18_LARGE_LEAK",
+ "CAN5_TRAY19_LARGE_LEAK", "CAN5_TRAY20_LARGE_LEAK",
+ "CAN5_TRAY21_LARGE_LEAK", "CAN5_TRAY22_LARGE_LEAK",
+ "CAN5_TRAY23_LARGE_LEAK", "CAN5_TRAY24_LARGE_LEAK",
+ "CAN5_TRAY25_LARGE_LEAK", "CAN5_TRAY26_LARGE_LEAK",
+ "CAN5_TRAY27_LARGE_LEAK", "CAN5_TRAY28_LARGE_LEAK",
+ "CAN5_TRAY29_LARGE_LEAK", "CAN5_TRAY30_LARGE_LEAK",
+ "CAN5_TRAY31_LARGE_LEAK", "CAN5_TRAY32_LARGE_LEAK",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ large_leak_io_expander5: gpio@55 {
+ compatible = "nxp,pca9698";
+ reg = <0x55>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <94 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN6_TRAY1_LARGE_LEAK", "CAN6_TRAY2_LARGE_LEAK",
+ "CAN6_TRAY3_LARGE_LEAK", "CAN6_TRAY4_LARGE_LEAK",
+ "CAN6_TRAY5_LARGE_LEAK", "CAN6_TRAY6_LARGE_LEAK",
+ "CAN6_TRAY7_LARGE_LEAK", "CAN6_TRAY8_LARGE_LEAK",
+ "CAN6_TRAY9_LARGE_LEAK", "CAN6_TRAY10_LARGE_LEAK",
+ "CAN6_TRAY11_LARGE_LEAK", "CAN6_TRAY12_LARGE_LEAK",
+ "CAN6_TRAY13_LARGE_LEAK", "CAN6_TRAY14_LARGE_LEAK",
+ "CAN6_TRAY15_LARGE_LEAK", "CAN6_TRAY16_LARGE_LEAK",
+ "CAN6_TRAY17_LARGE_LEAK", "CAN6_TRAY18_LARGE_LEAK",
+ "CAN6_TRAY19_LARGE_LEAK", "CAN6_TRAY20_LARGE_LEAK",
+ "CAN6_TRAY21_LARGE_LEAK", "CAN6_TRAY22_LARGE_LEAK",
+ "CAN6_TRAY23_LARGE_LEAK", "CAN6_TRAY24_LARGE_LEAK",
+ "CAN6_TRAY25_LARGE_LEAK", "CAN6_TRAY26_LARGE_LEAK",
+ "CAN6_TRAY27_LARGE_LEAK", "CAN6_TRAY28_LARGE_LEAK",
+ "CAN6_TRAY29_LARGE_LEAK", "CAN6_TRAY30_LARGE_LEAK",
+ "CAN6_TRAY31_LARGE_LEAK", "CAN6_TRAY32_LARGE_LEAK",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ large_leak_io_expander6: gpio@56 {
+ compatible = "nxp,pca9698";
+ reg = <0x56>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <102 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN7_TRAY1_LARGE_LEAK", "CAN7_TRAY2_LARGE_LEAK",
+ "CAN7_TRAY3_LARGE_LEAK", "CAN7_TRAY4_LARGE_LEAK",
+ "CAN7_TRAY5_LARGE_LEAK", "CAN7_TRAY6_LARGE_LEAK",
+ "CAN7_TRAY7_LARGE_LEAK", "CAN7_TRAY8_LARGE_LEAK",
+ "CAN7_TRAY9_LARGE_LEAK", "CAN7_TRAY10_LARGE_LEAK",
+ "CAN7_TRAY11_LARGE_LEAK", "CAN7_TRAY12_LARGE_LEAK",
+ "CAN7_TRAY13_LARGE_LEAK", "CAN7_TRAY14_LARGE_LEAK",
+ "CAN7_TRAY15_LARGE_LEAK", "CAN7_TRAY16_LARGE_LEAK",
+ "CAN7_TRAY17_LARGE_LEAK", "CAN7_TRAY18_LARGE_LEAK",
+ "CAN7_TRAY19_LARGE_LEAK", "CAN7_TRAY20_LARGE_LEAK",
+ "CAN7_TRAY21_LARGE_LEAK", "CAN7_TRAY22_LARGE_LEAK",
+ "CAN7_TRAY23_LARGE_LEAK", "CAN7_TRAY24_LARGE_LEAK",
+ "CAN7_TRAY25_LARGE_LEAK", "CAN7_TRAY26_LARGE_LEAK",
+ "CAN7_TRAY27_LARGE_LEAK", "CAN7_TRAY28_LARGE_LEAK",
+ "CAN7_TRAY29_LARGE_LEAK", "CAN7_TRAY30_LARGE_LEAK",
+ "CAN7_TRAY31_LARGE_LEAK", "CAN7_TRAY32_LARGE_LEAK",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ large_leak_io_expander7: gpio@57 {
+ compatible = "nxp,pca9698";
+ reg = <0x57>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <110 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN8_TRAY1_LARGE_LEAK", "CAN8_TRAY2_LARGE_LEAK",
+ "CAN8_TRAY3_LARGE_LEAK", "CAN8_TRAY4_LARGE_LEAK",
+ "CAN8_TRAY5_LARGE_LEAK", "CAN8_TRAY6_LARGE_LEAK",
+ "CAN8_TRAY7_LARGE_LEAK", "CAN8_TRAY8_LARGE_LEAK",
+ "CAN8_TRAY9_LARGE_LEAK", "CAN8_TRAY10_LARGE_LEAK",
+ "CAN8_TRAY11_LARGE_LEAK", "CAN8_TRAY12_LARGE_LEAK",
+ "CAN8_TRAY13_LARGE_LEAK", "CAN8_TRAY14_LARGE_LEAK",
+ "CAN8_TRAY15_LARGE_LEAK", "CAN8_TRAY16_LARGE_LEAK",
+ "CAN8_TRAY17_LARGE_LEAK", "CAN8_TRAY18_LARGE_LEAK",
+ "CAN8_TRAY19_LARGE_LEAK", "CAN8_TRAY20_LARGE_LEAK",
+ "CAN8_TRAY21_LARGE_LEAK", "CAN8_TRAY22_LARGE_LEAK",
+ "CAN8_TRAY23_LARGE_LEAK", "CAN8_TRAY24_LARGE_LEAK",
+ "CAN8_TRAY25_LARGE_LEAK", "CAN8_TRAY26_LARGE_LEAK",
+ "CAN8_TRAY27_LARGE_LEAK", "CAN8_TRAY28_LARGE_LEAK",
+ "CAN8_TRAY29_LARGE_LEAK", "CAN8_TRAY30_LARGE_LEAK",
+ "CAN8_TRAY31_LARGE_LEAK", "CAN8_TRAY32_LARGE_LEAK",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ small_leak_io_expander0: gpio@58 {
+ compatible = "nxp,pca9698";
+ reg = <0x58>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <52 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN1_TRAY1_SMALL_LEAK", "CAN1_TRAY2_SMALL_LEAK",
+ "CAN1_TRAY3_SMALL_LEAK", "CAN1_TRAY4_SMALL_LEAK",
+ "CAN1_TRAY5_SMALL_LEAK", "CAN1_TRAY6_SMALL_LEAK",
+ "CAN1_TRAY7_SMALL_LEAK", "CAN1_TRAY8_SMALL_LEAK",
+ "CAN1_TRAY9_SMALL_LEAK", "CAN1_TRAY10_SMALL_LEAK",
+ "CAN1_TRAY11_SMALL_LEAK", "CAN1_TRAY12_SMALL_LEAK",
+ "CAN1_TRAY13_SMALL_LEAK", "CAN1_TRAY14_SMALL_LEAK",
+ "CAN1_TRAY15_SMALL_LEAK", "CAN1_TRAY16_SMALL_LEAK",
+ "CAN1_TRAY17_SMALL_LEAK", "CAN1_TRAY18_SMALL_LEAK",
+ "CAN1_TRAY19_SMALL_LEAK", "CAN1_TRAY20_SMALL_LEAK",
+ "CAN1_TRAY21_SMALL_LEAK", "CAN1_TRAY22_SMALL_LEAK",
+ "CAN1_TRAY23_SMALL_LEAK", "CAN1_TRAY24_SMALL_LEAK",
+ "CAN1_TRAY25_SMALL_LEAK", "CAN1_TRAY26_SMALL_LEAK",
+ "CAN1_TRAY27_SMALL_LEAK", "CAN1_TRAY28_SMALL_LEAK",
+ "CAN1_TRAY29_SMALL_LEAK", "CAN1_TRAY30_SMALL_LEAK",
+ "CAN1_TRAY31_SMALL_LEAK", "CAN1_TRAY32_SMALL_LEAK",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ small_leak_io_expander1: gpio@59 {
+ compatible = "nxp,pca9698";
+ reg = <0x59>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <60 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN2_TRAY1_SMALL_LEAK", "CAN2_TRAY2_SMALL_LEAK",
+ "CAN2_TRAY3_SMALL_LEAK", "CAN2_TRAY4_SMALL_LEAK",
+ "CAN2_TRAY5_SMALL_LEAK", "CAN2_TRAY6_SMALL_LEAK",
+ "CAN2_TRAY7_SMALL_LEAK", "CAN2_TRAY8_SMALL_LEAK",
+ "CAN2_TRAY9_SMALL_LEAK", "CAN2_TRAY10_SMALL_LEAK",
+ "CAN2_TRAY11_SMALL_LEAK", "CAN2_TRAY12_SMALL_LEAK",
+ "CAN2_TRAY13_SMALL_LEAK", "CAN2_TRAY14_SMALL_LEAK",
+ "CAN2_TRAY15_SMALL_LEAK", "CAN2_TRAY16_SMALL_LEAK",
+ "CAN2_TRAY17_SMALL_LEAK", "CAN2_TRAY18_SMALL_LEAK",
+ "CAN2_TRAY19_SMALL_LEAK", "CAN2_TRAY20_SMALL_LEAK",
+ "CAN2_TRAY21_SMALL_LEAK", "CAN2_TRAY22_SMALL_LEAK",
+ "CAN2_TRAY23_SMALL_LEAK", "CAN2_TRAY24_SMALL_LEAK",
+ "CAN2_TRAY25_SMALL_LEAK", "CAN2_TRAY26_SMALL_LEAK",
+ "CAN2_TRAY27_SMALL_LEAK", "CAN2_TRAY28_SMALL_LEAK",
+ "CAN2_TRAY29_SMALL_LEAK", "CAN2_TRAY30_SMALL_LEAK",
+ "CAN2_TRAY31_SMALL_LEAK", "CAN2_TRAY32_SMALL_LEAK",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ small_leak_io_expander2: gpio@5a {
+ compatible = "nxp,pca9698";
+ reg = <0x5a>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <68 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN3_TRAY1_SMALL_LEAK", "CAN3_TRAY2_SMALL_LEAK",
+ "CAN3_TRAY3_SMALL_LEAK", "CAN3_TRAY4_SMALL_LEAK",
+ "CAN3_TRAY5_SMALL_LEAK", "CAN3_TRAY6_SMALL_LEAK",
+ "CAN3_TRAY7_SMALL_LEAK", "CAN3_TRAY8_SMALL_LEAK",
+ "CAN3_TRAY9_SMALL_LEAK", "CAN3_TRAY10_SMALL_LEAK",
+ "CAN3_TRAY11_SMALL_LEAK", "CAN3_TRAY12_SMALL_LEAK",
+ "CAN3_TRAY13_SMALL_LEAK", "CAN3_TRAY14_SMALL_LEAK",
+ "CAN3_TRAY15_SMALL_LEAK", "CAN3_TRAY16_SMALL_LEAK",
+ "CAN3_TRAY17_SMALL_LEAK", "CAN3_TRAY18_SMALL_LEAK",
+ "CAN3_TRAY19_SMALL_LEAK", "CAN3_TRAY20_SMALL_LEAK",
+ "CAN3_TRAY21_SMALL_LEAK", "CAN3_TRAY22_SMALL_LEAK",
+ "CAN3_TRAY23_SMALL_LEAK", "CAN3_TRAY24_SMALL_LEAK",
+ "CAN3_TRAY25_SMALL_LEAK", "CAN3_TRAY26_SMALL_LEAK",
+ "CAN3_TRAY27_SMALL_LEAK", "CAN3_TRAY28_SMALL_LEAK",
+ "CAN3_TRAY29_SMALL_LEAK", "CAN3_TRAY30_SMALL_LEAK",
+ "CAN3_TRAY31_SMALL_LEAK", "CAN3_TRAY32_SMALL_LEAK",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ small_leak_io_expander3: gpio@5b {
+ compatible = "nxp,pca9698";
+ reg = <0x5b>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <76 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN4_TRAY1_SMALL_LEAK", "CAN4_TRAY2_SMALL_LEAK",
+ "CAN4_TRAY3_SMALL_LEAK", "CAN4_TRAY4_SMALL_LEAK",
+ "CAN4_TRAY5_SMALL_LEAK", "CAN4_TRAY6_SMALL_LEAK",
+ "CAN4_TRAY7_SMALL_LEAK", "CAN4_TRAY8_SMALL_LEAK",
+ "CAN4_TRAY9_SMALL_LEAK", "CAN4_TRAY10_SMALL_LEAK",
+ "CAN4_TRAY11_SMALL_LEAK", "CAN4_TRAY12_SMALL_LEAK",
+ "CAN4_TRAY13_SMALL_LEAK", "CAN4_TRAY14_SMALL_LEAK",
+ "CAN4_TRAY15_SMALL_LEAK", "CAN4_TRAY16_SMALL_LEAK",
+ "CAN4_TRAY17_SMALL_LEAK", "CAN4_TRAY18_SMALL_LEAK",
+ "CAN4_TRAY19_SMALL_LEAK", "CAN4_TRAY20_SMALL_LEAK",
+ "CAN4_TRAY21_SMALL_LEAK", "CAN4_TRAY22_SMALL_LEAK",
+ "CAN4_TRAY23_SMALL_LEAK", "CAN4_TRAY24_SMALL_LEAK",
+ "CAN4_TRAY25_SMALL_LEAK", "CAN4_TRAY26_SMALL_LEAK",
+ "CAN4_TRAY27_SMALL_LEAK", "CAN4_TRAY28_SMALL_LEAK",
+ "CAN4_TRAY29_SMALL_LEAK", "CAN4_TRAY30_SMALL_LEAK",
+ "CAN4_TRAY31_SMALL_LEAK", "CAN4_TRAY32_SMALL_LEAK",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ small_leak_io_expander4: gpio@5c {
+ compatible = "nxp,pca9698";
+ reg = <0x5c>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <84 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN5_TRAY1_SMALL_LEAK", "CAN5_TRAY2_SMALL_LEAK",
+ "CAN5_TRAY3_SMALL_LEAK", "CAN5_TRAY4_SMALL_LEAK",
+ "CAN5_TRAY5_SMALL_LEAK", "CAN5_TRAY6_SMALL_LEAK",
+ "CAN5_TRAY7_SMALL_LEAK", "CAN5_TRAY8_SMALL_LEAK",
+ "CAN5_TRAY9_SMALL_LEAK", "CAN5_TRAY10_SMALL_LEAK",
+ "CAN5_TRAY11_SMALL_LEAK", "CAN5_TRAY12_SMALL_LEAK",
+ "CAN5_TRAY13_SMALL_LEAK", "CAN5_TRAY14_SMALL_LEAK",
+ "CAN5_TRAY15_SMALL_LEAK", "CAN5_TRAY16_SMALL_LEAK",
+ "CAN5_TRAY17_SMALL_LEAK", "CAN5_TRAY18_SMALL_LEAK",
+ "CAN5_TRAY19_SMALL_LEAK", "CAN5_TRAY20_SMALL_LEAK",
+ "CAN5_TRAY21_SMALL_LEAK", "CAN5_TRAY22_SMALL_LEAK",
+ "CAN5_TRAY23_SMALL_LEAK", "CAN5_TRAY24_SMALL_LEAK",
+ "CAN5_TRAY25_SMALL_LEAK", "CAN5_TRAY26_SMALL_LEAK",
+ "CAN5_TRAY27_SMALL_LEAK", "CAN5_TRAY28_SMALL_LEAK",
+ "CAN5_TRAY29_SMALL_LEAK", "CAN5_TRAY30_SMALL_LEAK",
+ "CAN5_TRAY31_SMALL_LEAK", "CAN5_TRAY32_SMALL_LEAK",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ small_leak_io_expander5: gpio@5d {
+ compatible = "nxp,pca9698";
+ reg = <0x5d>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <92 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN6_TRAY1_SMALL_LEAK", "CAN6_TRAY2_SMALL_LEAK",
+ "CAN6_TRAY3_SMALL_LEAK", "CAN6_TRAY4_SMALL_LEAK",
+ "CAN6_TRAY5_SMALL_LEAK", "CAN6_TRAY6_SMALL_LEAK",
+ "CAN6_TRAY7_SMALL_LEAK", "CAN6_TRAY8_SMALL_LEAK",
+ "CAN6_TRAY9_SMALL_LEAK", "CAN6_TRAY10_SMALL_LEAK",
+ "CAN6_TRAY11_SMALL_LEAK", "CAN6_TRAY12_SMALL_LEAK",
+ "CAN6_TRAY13_SMALL_LEAK", "CAN6_TRAY14_SMALL_LEAK",
+ "CAN6_TRAY15_SMALL_LEAK", "CAN6_TRAY16_SMALL_LEAK",
+ "CAN6_TRAY17_SMALL_LEAK", "CAN6_TRAY18_SMALL_LEAK",
+ "CAN6_TRAY19_SMALL_LEAK", "CAN6_TRAY20_SMALL_LEAK",
+ "CAN6_TRAY21_SMALL_LEAK", "CAN6_TRAY22_SMALL_LEAK",
+ "CAN6_TRAY23_SMALL_LEAK", "CAN6_TRAY24_SMALL_LEAK",
+ "CAN6_TRAY25_SMALL_LEAK", "CAN6_TRAY26_SMALL_LEAK",
+ "CAN6_TRAY27_SMALL_LEAK", "CAN6_TRAY28_SMALL_LEAK",
+ "CAN6_TRAY29_SMALL_LEAK", "CAN6_TRAY30_SMALL_LEAK",
+ "CAN6_TRAY31_SMALL_LEAK", "CAN6_TRAY32_SMALL_LEAK",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ small_leak_io_expander6: gpio@5e {
+ compatible = "nxp,pca9698";
+ reg = <0x5e>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <100 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN7_TRAY1_SMALL_LEAK", "CAN7_TRAY2_SMALL_LEAK",
+ "CAN7_TRAY3_SMALL_LEAK", "CAN7_TRAY4_SMALL_LEAK",
+ "CAN7_TRAY5_SMALL_LEAK", "CAN7_TRAY6_SMALL_LEAK",
+ "CAN7_TRAY7_SMALL_LEAK", "CAN7_TRAY8_SMALL_LEAK",
+ "CAN7_TRAY9_SMALL_LEAK", "CAN7_TRAY10_SMALL_LEAK",
+ "CAN7_TRAY11_SMALL_LEAK", "CAN7_TRAY12_SMALL_LEAK",
+ "CAN7_TRAY13_SMALL_LEAK", "CAN7_TRAY14_SMALL_LEAK",
+ "CAN7_TRAY15_SMALL_LEAK", "CAN7_TRAY16_SMALL_LEAK",
+ "CAN7_TRAY17_SMALL_LEAK", "CAN7_TRAY18_SMALL_LEAK",
+ "CAN7_TRAY19_SMALL_LEAK", "CAN7_TRAY20_SMALL_LEAK",
+ "CAN7_TRAY21_SMALL_LEAK", "CAN7_TRAY22_SMALL_LEAK",
+ "CAN7_TRAY23_SMALL_LEAK", "CAN7_TRAY24_SMALL_LEAK",
+ "CAN7_TRAY25_SMALL_LEAK", "CAN7_TRAY26_SMALL_LEAK",
+ "CAN7_TRAY27_SMALL_LEAK", "CAN7_TRAY28_SMALL_LEAK",
+ "CAN7_TRAY29_SMALL_LEAK", "CAN7_TRAY30_SMALL_LEAK",
+ "CAN7_TRAY31_SMALL_LEAK", "CAN7_TRAY32_SMALL_LEAK",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ small_leak_io_expander7: gpio@5f {
+ compatible = "nxp,pca9698";
+ reg = <0x5f>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <108 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "CAN8_TRAY1_SMALL_LEAK", "CAN8_TRAY2_SMALL_LEAK",
+ "CAN8_TRAY3_SMALL_LEAK", "CAN8_TRAY4_SMALL_LEAK",
+ "CAN8_TRAY5_SMALL_LEAK", "CAN8_TRAY6_SMALL_LEAK",
+ "CAN8_TRAY7_SMALL_LEAK", "CAN8_TRAY8_SMALL_LEAK",
+ "CAN8_TRAY9_SMALL_LEAK", "CAN8_TRAY10_SMALL_LEAK",
+ "CAN8_TRAY11_SMALL_LEAK", "CAN8_TRAY12_SMALL_LEAK",
+ "CAN8_TRAY13_SMALL_LEAK", "CAN8_TRAY14_SMALL_LEAK",
+ "CAN8_TRAY15_SMALL_LEAK", "CAN8_TRAY16_SMALL_LEAK",
+ "CAN8_TRAY17_SMALL_LEAK", "CAN8_TRAY18_SMALL_LEAK",
+ "CAN8_TRAY19_SMALL_LEAK", "CAN8_TRAY20_SMALL_LEAK",
+ "CAN8_TRAY21_SMALL_LEAK", "CAN8_TRAY22_SMALL_LEAK",
+ "CAN8_TRAY23_SMALL_LEAK", "CAN8_TRAY24_SMALL_LEAK",
+ "CAN8_TRAY25_SMALL_LEAK", "CAN8_TRAY26_SMALL_LEAK",
+ "CAN8_TRAY27_SMALL_LEAK", "CAN8_TRAY28_SMALL_LEAK",
+ "CAN8_TRAY29_SMALL_LEAK", "CAN8_TRAY30_SMALL_LEAK",
+ "CAN8_TRAY31_SMALL_LEAK", "CAN8_TRAY32_SMALL_LEAK",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+};
+
+&i2c4 {
+ status = "okay";
+ multi-master;
+ mctp-controller;
+
+ mctp0: mctp@10 {
+ compatible = "mctp-i2c-controller";
+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>;
+ };
+
+ i2c-mux@77 {
+ compatible = "nxp,pca9548";
+ reg = <0x77>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ idle-state = <6>;
+
+ i2c4mux0ch0: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ io_expander3: gpio@23 {
+ compatible = "nxp,pca9555";
+ reg = <0x23>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&io_expander7>;
+ interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "", "",
+ "", "RST_I2CRST_MUX1_N",
+ "RST_I2CRST_MUX2_N", "RST_I2CRST_MUX3_N",
+ "RST_I2CRST_MUX4_N", "RST_I2CRST_MUX5_N",
+ "RST_I2CRST_MUX6_N", "RST_I2CRST_MUX7_N",
+ "RST_I2CRST_MUX8_N", "",
+ "TRAY30_PWRGD_BUF_R", "TRAY31_PWRGD_BUF_R",
+ "TRAY32_PWRGD_BUF_R", "TRAY37_PWRGD_BUF_R";
+ };
+ };
+
+ i2c4mux0ch1: i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ temp-sensor@48 {
+ compatible = "ti,tmp75";
+ reg = <0x48>;
+ };
+
+ temp-sensor@4a {
+ compatible = "ti,tmp75";
+ reg = <0x4a>;
+ };
+
+ eeprom@56 {
+ compatible = "atmel,24c128";
+ reg = <0x56>;
+ };
+ };
+
+ i2c4mux0ch2: i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ status = "okay";
+ };
+
+ i2c4mux0ch3: i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ status = "okay";
+ };
+
+ i2c4mux0ch4: i2c@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+ status = "okay";
+ };
+
+ i2c4mux0ch5: i2c@5 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <5>;
+ status = "okay";
+ };
+
+ i2c4mux0ch6: i2c@6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6>;
+ mctp-controller;
+ };
+
+ i2c4mux0ch7: i2c@7 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <7>;
+ status = "okay";
+ };
+ };
+};
+
+&i2c5 {
+ status = "okay";
+
+ io_expander4: gpio@22 {
+ compatible = "nxp,pca9555";
+ reg = <0x22>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&io_expander7>;
+ interrupts = <4 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "R_COME_THERMTRIP_L", "R_PWRGD_PCH_PWROK",
+ "", "",
+ "", "",
+ "", "",
+ "", "",
+ "", "",
+ "", "TRAY38_PWRGD_BUF_R",
+ "TRAY39_PWRGD_BUF_R", "TRAY40_PWRGD_BUF_R";
+ };
+
+ io_expander5: gpio@23 {
+ compatible = "nxp,pca9555";
+ reg = <0x23>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&io_expander7>;
+ interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "PWRGD_P5V_AUX_R2", "",
+ "PWRGD_P1V5_AUX_R", "PWRGD_P1V05_AUX_R",
+ "PWRGD_P52V_HSC_PWROK_R", "PWRGD_P24V_AUX_2_R",
+ "PWRGD_P24V_AUX_R", "PWRGD_P12V_AUX_R2",
+ "PWRGD_P12V_SCM_R", "P24V_AUX_INA230_ALERT_N_R",
+ "", "PRSNT_CAN1_MCIO_N",
+ "PRSNT_CAN2_MCIO_N", "PRSNT_AALC_MCIO_N",
+ "PRSNT_RACKMON_MCIO_N", "PRSNT_RIO_RACKMON_N";
+ };
+
+ temp-sensor@4f {
+ compatible = "ti,tmp75";
+ reg = <0x4f>;
+ };
+
+ eeprom@54 {
+ compatible = "atmel,24c128";
+ reg = <0x54>;
+ };
+
+ i2c-mux@77 {
+ compatible = "nxp,pca9548";
+ reg = <0x77>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ i2c-mux-idle-disconnect;
+
+ i2c5mux0ch0: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ };
+
+ i2c5mux0ch1: i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ };
+
+ i2c5mux0ch2: i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+
+ eeprom@56 {
+ compatible = "atmel,24c128";
+ reg = <0x56>;
+ };
+ };
+
+ i2c5mux0ch3: i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+
+ eeprom@56 {
+ compatible = "atmel,24c128";
+ reg = <0x56>;
+ };
+ };
+
+ i2c5mux0ch4: i2c@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+
+ eeprom@56 {
+ compatible = "atmel,24c128";
+ reg = <0x56>;
+ };
+ };
+
+ i2c5mux0ch5: i2c@5 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <5>;
+
+ eeprom@56 {
+ compatible = "atmel,24c128";
+ reg = <0x56>;
+ };
+ };
+
+ i2c5mux0ch6: i2c@6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6>;
+
+ eeprom@56 {
+ compatible = "atmel,24c128";
+ reg = <0x56>;
+ };
+ };
+
+ i2c5mux0ch7: i2c@7 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <7>;
+
+ eeprom@56 {
+ compatible = "atmel,24c128";
+ reg = <0x56>;
+ };
+ };
+ };
+};
+
+&i2c6 {
+ status = "okay";
+
+ dac@c {
+ reg = <0x0c>;
+ compatible = "adi,ad5612";
+ vcc-supply = <&p5v_dac_aux>;
+ };
+
+ dac@e {
+ reg = <0x0e>;
+ compatible = "adi,ad5612";
+ vcc-supply = <&p5v_dac_aux>;
+ };
+
+ dac@f {
+ reg = <0x0f>;
+ compatible = "adi,ad5612";
+ vcc-supply = <&p5v_dac_aux>;
+ };
+
+ io_expander0: gpio@20 {
+ compatible = "nxp,pca9555";
+ reg = <0x20>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&io_expander7>;
+ /*
+ * Note: io_expander0 and io_expander8 physically share the
+ * same interrupt line (Wired-OR) to io_expander7 pin 0.
+ */
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "", "",
+ "", "",
+ "", "PRSNT_FANBP_0_PWR_N",
+ "PRSNT_FANBP_0_SIG_N", "PRSNT_POE_PWR_N",
+ "PRSNT_POE_SIG_N", "",
+ "PWRGD_P3V3_ISO_POE_BMC_R", "",
+ "", "",
+ "DEV_DIS_N", "PCI_DIS_N";
+ };
+
+ io_expander1: gpio@21 {
+ compatible = "nxp,pca9555";
+ reg = <0x21>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&io_expander7>;
+ interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "PWRGD_CPU_LVC3_BMC", "R_FM_BIOS_POST_CMPLT_BMC",
+ "", "",
+ "", "",
+ "", "",
+ "", "",
+ "", "PCIE_SSD1_PRSNT_N",
+ "", "TRAY23_PWRGD_BUF_R",
+ "TRAY24_PWRGD_BUF_R", "TRAY29_PWRGD_BUF_R";
+ };
+
+ io_expander2: gpio@22 {
+ compatible = "nxp,pca9555";
+ reg = <0x22>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&io_expander7>;
+ interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "BOARD_ID_0", "BOARD_ID_1",
+ "BOARD_ID_2", "BOARD_ID_3",
+ "SKU_ID_3", "SKU_ID_2",
+ "SKU_ID_1", "SKU_ID_0",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ io_expander7: gpio@23 {
+ compatible = "nxp,pca9555";
+ reg = <0x23>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <32 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "IOEXP1_INT_N", "IOEXP2_INT_N",
+ "IOEXP3_INT_N", "IOEXP4_INT_N",
+ "IOEXP5_INT_N", "IOEXP6_INT_N",
+ "IOEXP7_INT_N", "",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ io_expander8: gpio@24 {
+ compatible = "nxp,pca9555";
+ reg = <0x24>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&io_expander7>;
+ /* Shared interrupt line with io_expander0 */
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "PRSNT_MGMT_J54_N", "PRSNT_RACKMON_J47_N",
+ "PRSNT_MGMT_DEBUG_J53_N", "PRSNT_MINISAS_TOP_J49_N",
+ "PRSNT_MINISAS_TOP_J50_N", "PRSNT_MINISAS_BOT_J51_N",
+ "PRSNT_MINISAS_BOT_J52_N", "JTAG_PLD_JTAGEN",
+ "PU_PLD_CONFIG_N", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ /*
+ * This EEPROM is physically isolated by a hardware I2C multiplexer.
+ * By default, it is connected directly to the Marvell switch for
+ * routine configuration loading. The BMC only routes the EEPROM to
+ * its own I2C bus for out-of-band firmware updates while the switch
+ * is held in reset by the CPLD, ensuring no concurrent access.
+ */
+ eeprom@50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+
+ rtc@51 {
+ compatible = "nxp,pcf8563";
+ reg = <0x51>;
+ };
+};
+
+&i2c7 {
+ status = "okay";
+ bus-frequency = <100000>;
+ multi-master;
+ aspeed,hw-timeout-ms = <1000>;
+
+ ipmb@10 {
+ compatible = "ipmb-dev";
+ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>;
+ i2c-protocol;
+ };
+};
+
+&i2c8 {
+ status = "okay";
+
+ i2c-mux@77 {
+ compatible = "nxp,pca9548";
+ reg = <0x77>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ i2c-mux-idle-disconnect;
+
+ i2c8mux0ch0: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ status = "okay";
+ };
+
+ i2c8mux0ch1: i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ status = "okay";
+ };
+
+ i2c8mux0ch2: i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ status = "okay";
+ };
+
+ i2c8mux0ch3: i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ status = "okay";
+ };
+
+ i2c8mux0ch4: i2c@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+ status = "okay";
+ };
+
+ i2c8mux0ch5: i2c@5 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <5>;
+ status = "okay";
+ };
+
+ i2c8mux0ch6: i2c@6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6>;
+ status = "okay";
+ };
+
+ i2c8mux0ch7: i2c@7 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <7>;
+ status = "okay";
+ };
+ };
+};
+
+&i2c9 {
+ status = "okay";
+
+ temperature-sensor@4b {
+ compatible = "ti,tmp75";
+ reg = <0x4b>;
+ };
+
+ eeprom@50 {
+ compatible = "atmel,24c128";
+ reg = <0x50>;
+ };
+
+ eeprom@51 {
+ compatible = "atmel,24c128";
+ reg = <0x51>;
+ };
+
+ eeprom@56 {
+ compatible = "atmel,24c64";
+ reg = <0x56>;
+ };
+};
+
+&i2c10 {
+ status = "okay";
+ /*
+ * This board physically routes two sets of presence signals to support
+ * both new and older tray designs concurrently.
+ * The 'legacy_' prefix is used to distinguish these backward-compatible
+ * PCA9555 expanders from the new CAN-based PCA9698 expanders (e.g., gpio@40)
+ * and to prevent device tree label collisions.
+ */
+ legacy_prsnt_io_expander0: gpio@11 {
+ compatible = "nxp,pca9555";
+ reg = <0x11>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <40 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "TRAY_PRSNT1_N_BUF_R", "TRAY_PRSNT2_N_BUF_R",
+ "TRAY_PRSNT3_N_BUF_R", "TRAY_PRSNT4_N_BUF_R",
+ "TRAY_PRSNT5_N_BUF_R", "TRAY_PRSNT6_N_BUF_R",
+ "TRAY_PRSNT7_N_BUF_R", "TRAY_PRSNT8_N_BUF_R",
+ "TRAY_PRSNT9_N_BUF_R", "TRAY_PRSNT10_N_BUF_R",
+ "TRAY_PRSNT11_N_BUF_R", "TRAY_PRSNT12_N_BUF_R",
+ "TRAY_PRSNT13_N_BUF_R", "TRAY_PRSNT14_N_BUF_R",
+ "TRAY_PRSNT15_N_BUF_R", "TRAY_PRSNT16_N_BUF_R";
+ };
+
+ legacy_prsnt_io_expander1: gpio@12 {
+ compatible = "nxp,pca9555";
+ reg = <0x12>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <40 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "TRAY_PRSNT17_N_BUF_R", "TRAY_PRSNT18_N_BUF_R",
+ "TRAY_PRSNT19_N_BUF_R", "TRAY_PRSNT20_N_BUF_R",
+ "TRAY_PRSNT21_N_BUF_R", "TRAY_PRSNT22_N_BUF_R",
+ "TRAY_PRSNT23_N_BUF_R", "TRAY_PRSNT24_N_BUF_R",
+ "TRAY_PRSNT25_N_BUF_R", "TRAY_PRSNT26_N_BUF_R",
+ "TRAY_PRSNT27_N_BUF_R", "TRAY_PRSNT28_N_BUF_R",
+ "TRAY_PRSNT29_N_BUF_R", "TRAY_PRSNT30_N_BUF_R",
+ "TRAY_PRSNT31_N_BUF_R", "TRAY_PRSNT32_N_BUF_R";
+ };
+
+ legacy_prsnt_io_expander2: gpio@13 {
+ compatible = "nxp,pca9555";
+ reg = <0x13>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <40 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "TRAY_PRSNT33_N_BUF_R", "TRAY_PRSNT34_N_BUF_R",
+ "TRAY_PRSNT35_N_BUF_R", "TRAY_PRSNT36_N_BUF_R",
+ "TRAY_PRSNT37_N_BUF_R", "TRAY_PRSNT38_N_BUF_R",
+ "TRAY_PRSNT39_N_BUF_R", "TRAY_PRSNT40_N_BUF_R",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ power-monitor@14 {
+ compatible = "infineon,xdp710";
+ reg = <0x14>;
+ };
+
+ legacy_pwrgd_io_expander1: gpio@15 {
+ compatible = "nxp,pca9555";
+ reg = <0x15>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "TRAY_PWRGD17_N_BUF_R", "TRAY_PWRGD18_N_BUF_R",
+ "TRAY_PWRGD19_N_BUF_R", "TRAY_PWRGD20_N_BUF_R",
+ "TRAY_PWRGD21_N_BUF_R", "TRAY_PWRGD22_N_BUF_R",
+ "TRAY_PWRGD23_N_BUF_R", "TRAY_PWRGD24_N_BUF_R",
+ "TRAY_PWRGD25_N_BUF_R", "TRAY_PWRGD26_N_BUF_R",
+ "TRAY_PWRGD27_N_BUF_R", "TRAY_PWRGD28_N_BUF_R",
+ "TRAY_PWRGD29_N_BUF_R", "TRAY_PWRGD30_N_BUF_R",
+ "TRAY_PWRGD31_N_BUF_R", "TRAY_PWRGD32_N_BUF_R";
+ };
+
+ legacy_pwrgd_io_expander2: gpio@16 {
+ compatible = "nxp,pca9555";
+ reg = <0x16>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "TRAY_PWRGD33_N_BUF_R", "TRAY_PWRGD34_N_BUF_R",
+ "TRAY_PWRGD35_N_BUF_R", "TRAY_PWRGD36_N_BUF_R",
+ "TRAY_PWRGD37_N_BUF_R", "TRAY_PWRGD38_N_BUF_R",
+ "TRAY_PWRGD39_N_BUF_R", "TRAY_PWRGD40_N_BUF_R",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ legacy_leak_io_expander0: gpio@17 {
+ compatible = "nxp,pca9555";
+ reg = <0x17>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <46 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "TRAY_LEAK_DETECT1_N_BUF_R", "TRAY_LEAK_DETECT2_N_BUF_R",
+ "TRAY_LEAK_DETECT3_N_BUF_R", "TRAY_LEAK_DETECT4_N_BUF_R",
+ "TRAY_LEAK_DETECT5_N_BUF_R", "TRAY_LEAK_DETECT6_N_BUF_R",
+ "TRAY_LEAK_DETECT7_N_BUF_R", "TRAY_LEAK_DETECT8_N_BUF_R",
+ "TRAY_LEAK_DETECT9_N_BUF_R", "TRAY_LEAK_DETECT10_N_BUF_R",
+ "TRAY_LEAK_DETECT11_N_BUF_R", "TRAY_LEAK_DETECT12_N_BUF_R",
+ "TRAY_LEAK_DETECT13_N_BUF_R", "TRAY_LEAK_DETECT14_N_BUF_R",
+ "TRAY_LEAK_DETECT15_N_BUF_R", "TRAY_LEAK_DETECT16_N_BUF_R";
+ };
+
+ legacy_leak_io_expander1: gpio@18 {
+ compatible = "nxp,pca9555";
+ reg = <0x18>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <46 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "TRAY_LEAK_DETECT17_N_BUF_R", "TRAY_LEAK_DETECT18_N_BUF_R",
+ "TRAY_LEAK_DETECT19_N_BUF_R", "TRAY_LEAK_DETECT20_N_BUF_R",
+ "TRAY_LEAK_DETECT21_N_BUF_R", "TRAY_LEAK_DETECT22_N_BUF_R",
+ "TRAY_LEAK_DETECT23_N_BUF_R", "TRAY_LEAK_DETECT24_N_BUF_R",
+ "TRAY_LEAK_DETECT25_N_BUF_R", "TRAY_LEAK_DETECT26_N_BUF_R",
+ "TRAY_LEAK_DETECT27_N_BUF_R", "TRAY_LEAK_DETECT28_N_BUF_R",
+ "TRAY_LEAK_DETECT29_N_BUF_R", "TRAY_LEAK_DETECT30_N_BUF_R",
+ "TRAY_LEAK_DETECT31_N_BUF_R", "TRAY_LEAK_DETECT32_N_BUF_R";
+ };
+
+ legacy_leak_io_expander2: gpio@19 {
+ compatible = "nxp,pca9555";
+ reg = <0x19>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <46 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "TRAY_LEAK_DETECT33_N_BUF_R", "TRAY_LEAK_DETECT34_N_BUF_R",
+ "TRAY_LEAK_DETECT35_N_BUF_R", "TRAY_LEAK_DETECT36_N_BUF_R",
+ "TRAY_LEAK_DETECT37_N_BUF_R", "TRAY_LEAK_DETECT38_N_BUF_R",
+ "TRAY_LEAK_DETECT39_N_BUF_R", "TRAY_LEAK_DETECT40_N_BUF_R",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ legacy_small_leak_io_expander0: gpio@1a {
+ compatible = "nxp,pca9555";
+ reg = <0x1a>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <44 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "TRAY_SMALL_LEAK1_N_BUF_R", "TRAY_SMALL_LEAK2_N_BUF_R",
+ "TRAY_SMALL_LEAK3_N_BUF_R", "TRAY_SMALL_LEAK4_N_BUF_R",
+ "TRAY_SMALL_LEAK5_N_BUF_R", "TRAY_SMALL_LEAK6_N_BUF_R",
+ "TRAY_SMALL_LEAK7_N_BUF_R", "TRAY_SMALL_LEAK8_N_BUF_R",
+ "TRAY_SMALL_LEAK9_N_BUF_R", "TRAY_SMALL_LEAK10_N_BUF_R",
+ "TRAY_SMALL_LEAK11_N_BUF_R", "TRAY_SMALL_LEAK12_N_BUF_R",
+ "TRAY_SMALL_LEAK13_N_BUF_R", "TRAY_SMALL_LEAK14_N_BUF_R",
+ "TRAY_SMALL_LEAK15_N_BUF_R", "TRAY_SMALL_LEAK16_N_BUF_R";
+ };
+
+ legacy_small_leak_io_expander1: gpio@1b {
+ compatible = "nxp,pca9555";
+ reg = <0x1b>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <44 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "TRAY_SMALL_LEAK17_N_BUF_R", "TRAY_SMALL_LEAK18_N_BUF_R",
+ "TRAY_SMALL_LEAK19_N_BUF_R", "TRAY_SMALL_LEAK20_N_BUF_R",
+ "TRAY_SMALL_LEAK21_N_BUF_R", "TRAY_SMALL_LEAK22_N_BUF_R",
+ "TRAY_SMALL_LEAK23_N_BUF_R", "TRAY_SMALL_LEAK24_N_BUF_R",
+ "TRAY_SMALL_LEAK25_N_BUF_R", "TRAY_SMALL_LEAK26_N_BUF_R",
+ "TRAY_SMALL_LEAK27_N_BUF_R", "TRAY_SMALL_LEAK28_N_BUF_R",
+ "TRAY_SMALL_LEAK29_N_BUF_R", "TRAY_SMALL_LEAK30_N_BUF_R",
+ "TRAY_SMALL_LEAK31_N_BUF_R", "TRAY_SMALL_LEAK32_N_BUF_R";
+ };
+
+ legacy_small_leak_io_expander2: gpio@1c {
+ compatible = "nxp,pca9555";
+ reg = <0x1c>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <44 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "TRAY_SMALL_LEAK33_N_BUF_R", "TRAY_SMALL_LEAK34_N_BUF_R",
+ "TRAY_SMALL_LEAK35_N_BUF_R", "TRAY_SMALL_LEAK36_N_BUF_R",
+ "TRAY_SMALL_LEAK37_N_BUF_R", "TRAY_SMALL_LEAK38_N_BUF_R",
+ "TRAY_SMALL_LEAK39_N_BUF_R", "TRAY_SMALL_LEAK40_N_BUF_R",
+ "", "",
+ "", "",
+ "", "",
+ "", "";
+ };
+
+ legacy_pwrgd_io_expander0: gpio@28 {
+ compatible = "nxp,pca9555";
+ reg = <0x28>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&sgpiom0>;
+ interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
+
+ gpio-line-names =
+ "TRAY_PWRGD1_N_BUF_R", "TRAY_PWRGD2_N_BUF_R",
+ "TRAY_PWRGD3_N_BUF_R", "TRAY_PWRGD4_N_BUF_R",
+ "TRAY_PWRGD5_N_BUF_R", "TRAY_PWRGD6_N_BUF_R",
+ "TRAY_PWRGD7_N_BUF_R", "TRAY_PWRGD8_N_BUF_R",
+ "TRAY_PWRGD9_N_BUF_R", "TRAY_PWRGD10_N_BUF_R",
+ "TRAY_PWRGD11_N_BUF_R", "TRAY_PWRGD12_N_BUF_R",
+ "TRAY_PWRGD13_N_BUF_R", "TRAY_PWRGD14_N_BUF_R",
+ "TRAY_PWRGD15_N_BUF_R", "TRAY_PWRGD16_N_BUF_R";
+ };
+
+ adc@35 {
+ compatible = "maxim,max11617";
+ reg = <0x35>;
+ };
+
+ power-monitor@44 {
+ compatible = "lltc,ltc4287";
+ reg = <0x44>;
+ shunt-resistor-micro-ohms = <500>;
+ };
+
+ adc@48 {
+ compatible = "ti,ads1015";
+ reg = <0x48>;
+ };
+
+ temp-sensor@4c {
+ compatible = "ti,tmp75";
+ reg = <0x4c>;
+ };
+
+ temp-sensor@4d {
+ compatible = "ti,tmp75";
+ reg = <0x4d>;
+ };
+
+ temp-sensor@4e {
+ compatible = "ti,tmp75";
+ reg = <0x4e>;
+ };
+
+ power-monitor@4f {
+ compatible = "ti,ina230";
+ reg = <0x4f>;
+ shunt-resistor = <1000>;
+ };
+
+ power-monitor@69 {
+ compatible = "pmbus";
+ reg = <0x69>;
+ };
+
+ fpga_io_expander64: gpio@64 {
+ compatible = "nxp,pca9555";
+ reg = <0x64>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ gpio-line-names =
+ "", "",
+ "", "",
+ "", "",
+ "LEAK_CONFIG0", "LEAK_CONFIG1",
+ "FPGA_PWRGD_P24V_AUX_R", "FPGA_PWRGD_P24V_AUX_2_R",
+ "FPGA_PWRGD_P12V_SCM_R", "FPGA_PWRGD_P12V_AUX_R2",
+ "FPGA_PRSNT_FANBP_0_SIG_R_PLD_N", "FPGA_PRSNT_FANBP_0_PWR_R_PLD_N",
+ "FPGA_P24V_AUX_INA230_ALERT_N_R", "FPGA_SMB_TMC75_TEMP_ALERT_N_R";
+ };
+
+ fpga_io_expander65: gpio@65 {
+ compatible = "nxp,pca9555";
+ reg = <0x65>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ gpio-line-names =
+ "FPGA_PCI_DIS_N", "FPGA_DEV_DIS_N",
+ "FPGA_PWRGD_P3V3_AUX_R", "FPGA_PWRGD_P5V_AUX_R2",
+ "FPGA_PWRGD_P1V05_AUX_R", "FPGA_P48V_HSC_ALERT_N",
+ "FPGA_PWRGD_P1V5_AUX_R", "FPGA_PWRGD_P52V_HSC_PWROK_R",
+ "FPGA_R_COME_THERMTRIP_L", "FPGA_PRSNT_POE_SIG_PLD_N",
+ "FPGA_PRSNT_POE_PWR_PLD_N", "FPGA_PRSNT_RIO_RACKMON_N",
+ "FPGA_PRSNT_CAN2_MCIO_N", "FPGA_PRSNT_CAN1_MCIO_N",
+ "FPGA_PRSNT_RACKMON_MCIO_N", "FPGA_PRSNT_AALC_MCIO_N";
+ };
+
+ fpga_io_expander66: gpio@66 {
+ compatible = "nxp,pca9555";
+ reg = <0x66>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ gpio-line-names =
+ "FPGA_R_FM_CPU_ERR0_LVT3_L", "FPGA_FPGA_R_FM_PCHHOT_L",
+ "FPGA_R_FM_BIOS_POST_CMPLT_L", "FPGA_R_FM_SOC_BMC_RST_L",
+ "FPGA_R_CPU_MSMI_CATERR_N", "FPGA_R_H_MEMHOT_OUT_FET_L",
+ "FPGA_R_PWRGD_P3V3_STBY", "FPGA_R_PWRGD_PCH_PWROK",
+ "FPGA_TRAY23_PWRGD_BUF_R", "FPGA_TRAY24_PWRGD_BUF_R",
+ "FPGA_P24V_AUX_2_INA230_ALERT_N_R", "FPGA_R_IRQ_BMC_PCH_SMI_N",
+ "FPGA_R_FM_CPU_DIMM_EVENT_COD_BUF", "FPGA_R_BIOS_MSG_DIS_L",
+ "FPGA_R_ISO_FM_USB_OC0_L", "FPGA_SPI_LVC_EN";
+ };
+
+ fpga_io_expander67: gpio@67 {
+ compatible = "nxp,pca9555";
+ reg = <0x67>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ gpio-line-names =
+ "FPGA_TRAY29_PWRGD_BUF_R", "FPGA_TRAY30_PWRGD_BUF_R",
+ "FPGA_TRAY31_PWRGD_BUF_R", "FPGA_TRAY32_PWRGD_BUF_R",
+ "FPGA_TRAY37_PWRGD_BUF_R", "FPGA_TRAY38_PWRGD_BUF_R",
+ "FPGA_TRAY39_PWRGD_BUF_R", "FPGA_TRAY40_PWRGD_BUF_R",
+ "FPGA_ISO_CARRIER_BOARD_PWR_OK", "FPGA_UART_MUX_SEL",
+ "", "",
+ "", "",
+ "", "";
+ };
+};
+
+&i2c11 {
+ status = "okay";
+
+ i2c-mux@77 {
+ compatible = "nxp,pca9548";
+ reg = <0x77>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ i2c-mux-idle-disconnect;
+
+ i2c11mux0ch0: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ status = "okay";
+ };
+
+ i2c11mux0ch1: i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ status = "okay";
+ };
+
+ i2c11mux0ch2: i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ status = "okay";
+ };
+
+ i2c11mux0ch3: i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ status = "okay";
+ };
+
+ i2c11mux0ch4: i2c@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+ status = "okay";
+ };
+
+ i2c11mux0ch5: i2c@5 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <5>;
+ status = "okay";
+ };
+
+ i2c11mux0ch6: i2c@6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6>;
+ status = "okay";
+ };
+
+ i2c11mux0ch7: i2c@7 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <7>;
+ status = "okay";
+ };
+ };
+};
+
+&i2c12 {
+ status = "okay";
+ bus-frequency = <400000>;
+};
+
+&i2c13 {
+ status = "okay";
+
+ i2c-mux@77 {
+ compatible = "nxp,pca9548";
+ reg = <0x77>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ i2c-mux-idle-disconnect;
+
+ i2c13mux0ch0: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ status = "okay";
+ };
+
+ i2c13mux0ch1: i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ status = "okay";
+ };
+
+ i2c13mux0ch2: i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ status = "okay";
+ };
+
+ i2c13mux0ch3: i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ status = "okay";
+ };
+
+ i2c13mux0ch4: i2c@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+ status = "okay";
+ };
+
+ i2c13mux0ch5: i2c@5 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <5>;
+ status = "okay";
+ };
+
+ i2c13mux0ch6: i2c@6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6>;
+ status = "okay";
+ };
+
+ i2c13mux0ch7: i2c@7 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <7>;
+ status = "okay";
+ };
+ };
+};
+
+&i2c14 {
+ status = "okay";
+};
+
+&i2c15 {
+ status = "okay";
+
+ i2c-mux@77 {
+ compatible = "nxp,pca9548";
+ reg = <0x77>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ i2c-mux-idle-disconnect;
+
+ i2c15mux0ch0: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ status = "okay";
+ };
+
+ i2c15mux0ch1: i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ status = "okay";
+ };
+
+ i2c15mux0ch2: i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ status = "okay";
+ };
+
+ i2c15mux0ch3: i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ status = "okay";
+ };
+
+ i2c15mux0ch4: i2c@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+ status = "okay";
+ };
+
+ i2c15mux0ch5: i2c@5 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <5>;
+ status = "okay";
+ };
+
+ i2c15mux0ch6: i2c@6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6>;
+ status = "okay";
+ };
+
+ i2c15mux0ch7: i2c@7 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <7>;
+ status = "okay";
+ };
+ };
+};
+
+&kcs3 {
+ aspeed,lpc-io-reg = <0xca2>;
+ status = "okay";
+};
+
+&lpc_ctrl {
+ status = "okay";
+};
+
+&mac2 {
+ status = "okay";
+ phy-mode = "rmii";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rmii3_default>;
+
+ /*
+ * The Marvell 88E6393X is initialized at boot via EEPROM
+ * configuration and hardware straps.
+ * The BMC connects via an RMII fixed-link; link parameters are fixed
+ * by board design.
+ */
+ fixed-link {
+ speed = <100>;
+ full-duplex;
+ };
+};
+
+&mac3 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rmii4_default>;
+ use-ncsi;
+};
+
+&peci0 {
+ status = "okay";
+};
+
+&sgpiom0 {
+ status = "okay";
+ ngpios = <128>;
+ bus-frequency = <100000>;
+ gpio-line-names =
+ /*"input pin","output pin"*/
+ /*A0 - A7*/
+ "power-chassis-good","FM_PLD_HEARTBEAT_LVC3_R",
+ "host0-ready","R_BMC_PTH_RST_BTN_L",
+ "CONTROL_VT2_SUPPLY1_CLOSE","FM_MDIO_SW_SEL_PLD",
+ "CONTROL_VT2_SUPPLY2_CLOSE","FM_88E6393X_BIN_UPDATE_EN_N",
+ "CONTROL_VT2_SUPPLY3_CLOSE","Sequence_TransFR_Alert",
+ "RETURN_CNTL1_FB","WATER_VALVE1_OPEN",
+ "RETURN_CNTL2_FB","WATER_VALVE2_OPEN",
+ "RETURN_CNTL3_FB","WATER_VALVE3_OPEN",
+ /*B0 - B7*/
+ "IT_STOP_PUMP_R_CPLD","WATER_VALVE1_CLOSE",
+ "IT_STOP_PUMP_SPARE_R_CPLD","WATER_VALVE2_CLOSE",
+ "IT_STOP_PUMP_2_R_CPLD","WATER_VALVE3_CLOSE",
+ "IT_STOP_PUMP_SPARE_2_R_CPLD","REPORT_VT2_SUPPLY1_CLOSE",
+ "RPU_2_READY_SPARE_PLD_R","REPORT_VT2_SUPPLY2_CLOSE",
+ "RPU_2_READY_PLD_R","REPORT_VT2_SUPPLY3_CLOSE",
+ "RPU_READY_SPARE_PLD_R","PCIE_SSD1_PRSNT_N",
+ "RPU_READY_PLD_R","",
+ /*C0 - C7*/
+ "IOEXP8_INT_N","",
+ "SUPPLY_CNTL1_FB","",
+ "SUPPLY_CNTL2_FB","",
+ "SUPPLY_CNTL3_FB","",
+ "PRSNT_TRAY1_TO_40_R_BUF_N","",
+ "PWRGD_TRAY1_TO_40_R_BUF","",
+ "SMALL_LEAK_TRAY1_TO_40_R_BUF_N","",
+ "LEAK_DETECT_TRAY1_TO_40_R_BUF_N","",
+ /*D0 - D7*/
+ "PRSNT_CANBUSP1_TRAY1_TO_32_N","",
+ "PWRGD_CANBUSP1_TRAY1_TO_32_PWROK","",
+ "SMALL_LEAK_CANBUSP1_TRAY1_TO_32_N","",
+ "LEAK_DETECT_CANBUSP1_TRAY1_TO_32_N","",
+ "PRSNT_CANBUSP2_TRAY1_TO_32_N","",
+ "PWRGD_CANBUSP2_TRAY1_TO_32_PWROK","",
+ "SMALL_LEAK_CANBUSP2_TRAY1_TO_32_N","",
+ "LEAK_DETECT_CANBUSP2_TRAY1_TO_32_N","",
+ /*E0 - E7*/
+ "PRSNT_CANBUSP3_TRAY1_TO_32_N","",
+ "PWRGD_CANBUSP3_TRAY1_TO_32_PWROK","",
+ "SMALL_LEAK_CANBUSP3_TRAY1_TO_32_N","",
+ "LEAK_DETECT_CANBUSP3_TRAY1_TO_32_N","",
+ "PRSNT_CANBUSP4_TRAY1_TO_32_N","",
+ "PWRGD_CANBUSP4_TRAY1_TO_32_PWROK","",
+ "SMALL_LEAK_CANBUSP4_TRAY1_TO_32_N","",
+ "LEAK_DETECT_CANBUSP4_TRAY1_TO_32_N","",
+ /*F0 - F7*/
+ "PRSNT_CANBUSP5_TRAY1_TO_32_N","",
+ "PWRGD_CANBUSP5_TRAY1_TO_32_PWROK","",
+ "SMALL_LEAK_CANBUSP5_TRAY1_TO_32_N","",
+ "LEAK_DETECT_CANBUSP5_TRAY1_TO_32_N","",
+ "PRSNT_CANBUSP6_TRAY1_TO_32_N","",
+ "PWRGD_CANBUSP6_TRAY1_TO_32_PWROK","",
+ "SMALL_LEAK_CANBUSP6_TRAY1_TO_32_N","",
+ "LEAK_DETECT_CANBUSP6_TRAY1_TO_32_N","",
+ /*G0 - G7*/
+ "PRSNT_CANBUSP7_TRAY1_TO_32_N","",
+ "PWRGD_CANBUSP7_TRAY1_TO_32_PWROK","",
+ "SMALL_LEAK_CANBUSP7_TRAY1_TO_32_N","",
+ "LEAK_DETECT_CANBUSP7_TRAY1_TO_32_N","",
+ "PRSNT_CANBUSP8_TRAY1_TO_32_N","",
+ "PWRGD_CANBUSP8_TRAY1_TO_32_PWROK","",
+ "SMALL_LEAK_CANBUSP8_TRAY1_TO_32_N","",
+ "LEAK_DETECT_CANBUSP8_TRAY1_TO_32_N","",
+ /*H0 - H7*/
+ "CHASSIS0_LEAK_Q_N_R","",
+ "CHASSIS1_LEAK_Q_N_R","",
+ "CHASSIS2_LEAK_Q_N_R","",
+ "CHASSIS3_LEAK_Q_N_R","",
+ "CHASSIS4_LEAK_Q_N_R","",
+ "CHASSIS5_LEAK_Q_N_R","",
+ "CHASSIS6_LEAK_Q_N_R","",
+ "CHASSIS7_LEAK_Q_N_R","",
+ /*I0 - I7*/
+ "CHASSIS8_LEAK_Q_N_R","",
+ "CHASSIS9_LEAK_Q_N_R","",
+ "CHASSIS10_LEAK_Q_N_R","",
+ "CHASSIS11_LEAK_Q_N_R","",
+ "AALC_RPU_READY","",
+ "","",
+ "","",
+ "","",
+ /*J0 - J7*/
+ "","",
+ "","",
+ "","",
+ "","",
+ "","",
+ "","",
+ "","",
+ "","",
+ /*K0 - K7*/
+ "","",
+ "","",
+ "","",
+ "","",
+ "","",
+ "","",
+ "","",
+ "","",
+ /*L0 - L7*/
+ "IT_GEAR_RPU_2_LINK_PRSNT_SPARE_N_R","",
+ "IT_GEAR_RPU_2_LINK_PRSNT_N_R","",
+ "IT_GEAR_RPU_LINK_PRSNT_SPARE_N_R","",
+ "IT_GEAR_RPU_LINK_PRSNT_N_R","",
+ "","",
+ "","",
+ "","",
+ "","",
+ /*M0 - M7*/
+ "","",
+ "","",
+ "PRSNT_SENSOR_N","",
+ "PRSNT3_VT2_PLD_N","",
+ "PRSNT2_VT2_PLD_N","",
+ "PRSNT1_VT2_PLD_N","",
+ "PRSNT3_RETURN_PLD_N","",
+ "PRSNT2_RETURN_PLD_N","",
+ /*N0 - N7*/
+ "PRSNT1_RETURN_PLD_N","",
+ "PRSNT3_SUPPLY_PLD_N","",
+ "PRSNT2_SUPPLY_PLD_N","",
+ "PRSNT1_SUPPLY_PLD_N","",
+ "PRSNT_LEAK11_SENSOR_R_PLD_N","",
+ "PRSNT_LEAK10_SENSOR_R_PLD_N","",
+ "PRSNT_LEAK9_SENSOR_R_PLD_N","",
+ "PRSNT_LEAK8_SENSOR_R_PLD_N","",
+ /*O0 - O7*/
+ "PRSNT_LEAK7_SENSOR_R_PLD_N","",
+ "PRSNT_LEAK6_SENSOR_R_PLD_N","",
+ "PRSNT_LEAK5_SENSOR_R_PLD_N","",
+ "PRSNT_LEAK4_SENSOR_R_PLD_N","",
+ "PRSNT_LEAK3_SENSOR_R_PLD_N","",
+ "PRSNT_LEAK2_SENSOR_R_PLD_N","",
+ "PRSNT_LEAK1_SENSOR_R_PLD_N","",
+ "PRSNT_LEAK0_SENSOR_R_PLD_N","",
+ /*P0 - P7*/
+ "","",
+ "","",
+ "","",
+ "","",
+ "","SGPIO_REG_VALID_0",
+ "","SGPIO_REG_VALID_1",
+ "","SGPIO_REG_VALID_2",
+ "","SGPIO_REG_VALID_3";
+};
+
+&spi2 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi2_default &pinctrl_spi2cs1_default>;
+
+ flash@0 {
+ status = "okay";
+ m25p,fast-read;
+ label = "pnor";
+ spi-max-frequency = <12000000>;
+ spi-tx-bus-width = <2>;
+ spi-rx-bus-width = <2>;
+ };
+
+ flash@1 {
+ status = "okay";
+ m25p,fast-read;
+ label = "e810";
+ spi-max-frequency = <12000000>;
+ spi-tx-bus-width = <2>;
+ spi-rx-bus-width = <2>;
+ };
+};
+
+&uart3 {
+ status = "okay";
+};
+
+&wdt1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wdtrst1_default>;
+ aspeed,reset-type = "soc";
+ aspeed,external-signal;
+ aspeed,ext-push-pull;
+ aspeed,ext-active-high;
+ aspeed,ext-pulse-duration = <256>;
+};
+
--
2.34.1
^ permalink raw reply related
* [PATCH v8 0/2] Add Meta(Facebook) ventura2 BMC(AST2600)
From: Kyle Hsieh @ 2026-06-15 2:46 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Joel Stanley,
Andrew Jeffery
Cc: devicetree, linux-arm-kernel, linux-aspeed, linux-kernel,
Kyle Hsieh, Krzysztof Kozlowski
Summary:
Add linux device tree entry related to Meta(Facebook) ventura2.
specific devices connected to BMC(AST2600) SoC.
Signed-off-by: Kyle Hsieh <kylehsieh1995@gmail.com>
---
Changes in v8:
- Addressed review comments from Andrew Lunn:
* Added a detailed comment to the Marvell 88E6393X EEPROM node to clarify its hardware I2C multiplexer isolation and out-of-band firmware update mechanism, explaining why there is no concurrent access or multi-master scenario.
- Link to v7: https://lore.kernel.org/r/20260611-ventura2_initial_dts-v7-0-a61d8902bc5f@gmail.com
Changes in v7:
- Updated the commit message to include a detailed description of the Ventura2 platform's purpose and its key hardware features.
- Fix comments from Andrew Jeffery:
* Ensured consistent blank lines to separate child nodes from parent properties and from each other throughout the DTS.
* Sorted fan nodes in ascending order.
* Replaced '//' comments with '/* */' block comments.
- Fix feedback from Sashiko AI:
* Added 'idle-state = <6>;' to the PCA9548 mux on i2c4.
- Link to v6: https://lore.kernel.org/r/20260610-ventura2_initial_dts-v6-0-375d8e9d7ebf@gmail.com
Changes in v6:
- Addressed automated feedback from Sashiko bot:
* Clarified comments that io_expander0 and io_expander8 physically share the same interrupt line (Wired-OR) by hardware design.
* Removed leading zeros from unit addresses in DAC nodes (dac@c, dac@e, dac@f).
* Removed unused properties from the adc@48 node.
- Link to v5: https://lore.kernel.org/r/20260608-ventura2_initial_dts-v5-0-37ee5bcf58b6@gmail.com
Changes in v5:
- Addressed review comments:
* Added comments explaining the necessity of 'legacy_' prefixes (hardware label collision), pre-allocated I2C aliases (future expansions), and the 'ledd1' naming convention (schematic alignment).
* Removed the empty `&mdio0` node to comply with upstream networking subsystem guidelines.
* Removed the redundant `&peci0` node.
* Sorted `&kcs3` and `&lpc_ctrl` nodes in strict alphabetical order.
- Hardware/DT alignment updates:
* Removed unpopulated sensors (adi,adt7461, infineon,tda38640, ti,ina230, ti,ina238) to accurately reflect the current board population.
* Added the secondary flash node (flash@1 labeled "e810") under the &spi2 bus.
- Link to v4: https://lore.kernel.org/r/20260424-ventura2_initial_dts-v4-0-806b00ea4314@gmail.com
Changes in v4:
- Fixed capitalization: "ventura2" -> "Ventura2".
- Reordered I2C child nodes in ascending order of unit addresses.
- Enable PECI, LPC control, and KCS3 interfaces for host communication.
- Configure MCTP controller on I2C4 and enable MCTP support for specific mux channels.
- Add Infineon TDA38640 and TI INA230 power monitor nodes.
- GPIO and Pinmux cleanup for PVT:
- Aligned gpio-line-names as requested.
- Remove unused or non-existent GPIO line names to align with Ventura2 PVT.
- Update specific GPIO pins to empty strings where signals were removed or consolidated.
- Adjust SGPIOM frequency to 200kHz and update signal line names.
- Enable UART3 and add serial2 alias.
- Link to v3: https://lore.kernel.org/r/20260113-ventura2_initial_dts-v3-0-2dbfda6a5b47@gmail.com
Changes in v3:
- Add annotation for marvel 88e6393x
- Modify the gpio-line-name
- Modify the node order alphabetically
- Modify dt-bindings document for rmc instead of bmc
- Move the gpio-line-names to original node
- Link to v2: https://lore.kernel.org/r/20251224-ventura2_initial_dts-v2-0-f193ba5d4073@gmail.com
Changes in v2:
- Remove unused mdio
- Link to v1: https://lore.kernel.org/r/20251222-ventura2_initial_dts-v1-0-1f06166c78a3@gmail.com
---
Kyle Hsieh (2):
dt-bindings: arm: aspeed: add Meta ventura2 board
ARM: dts: aspeed: ventura2: Add Meta ventura2 BMC
.../devicetree/bindings/arm/aspeed/aspeed.yaml | 1 +
arch/arm/boot/dts/aspeed/Makefile | 1 +
.../dts/aspeed/aspeed-bmc-facebook-ventura2.dts | 2903 ++++++++++++++++++++
3 files changed, 2905 insertions(+)
---
base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
change-id: 20251222-ventura2_initial_dts-909b3277d665
Best regards,
--
Kyle Hsieh <kylehsieh1995@gmail.com>
^ permalink raw reply
* [PATCH v3 3/3] arm64: escalate smp_send_stop() to an SDEI NMI as a last resort
From: Kiryl Shutsemau @ 2026-06-15 2:35 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, James Morse
Cc: Mark Rutland, Marc Zyngier, Doug Anderson, Petr Mladek,
Thomas Gleixner, Andrew Morton, Baoquan He, Puranjay Mohan,
Usama Arif, Breno Leitao, Julien Thierry, Lecopzer Chen,
Sumit Garg, kernel-team, kexec, linux-arm-kernel, linux-kernel,
Kiryl Shutsemau (Meta)
In-Reply-To: <cover.1781490440.git.kas@kernel.org>
From: "Kiryl Shutsemau (Meta)" <kas@kernel.org>
A CPU wedged with interrupts masked ignores the stop IPI, and without
pseudo-NMI there is no NMI IPI to escalate to: a reboot proceeds with
the CPU still running, and a kdump misses its registers.
Add a third rung to smp_send_stop(): once the IPI (and pseudo-NMI IPI,
if enabled) rungs have run, signal SDEI event 0 at whatever stayed
online. Firmware delivers it regardless of the target's DAIF, so it
reaches a CPU a plain IPI cannot; the target acks by going offline,
which the caller already polls for.
Fold the stop bookkeeping into one arm64_nmi_cpu_stop(regs,
die_on_crash), shared by the stop IPI handlers, panic_smp_self_stop()
and the SDEI handler, replacing the near-duplicate local_cpu_stop() and
ipi_cpu_crash_stop(). @die_on_crash is the only difference: the IPI
handlers pass true and PSCI CPU_OFF the CPU on a crash stop so a capture
kernel can reclaim it; the SDEI handler and self-stop pass false and
park. The SDEI park is required, not conservative -- its handler runs
inside an SDEI event that is never completed (completing it resumes the
wedged context), and a CPU_OFF from that unfinished-event context wedges
EL3 on some firmware (left as a follow-up). The dump is unaffected; only
re-onlining the CPU in an SMP capture kernel is lost.
Suggested-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
---
arch/arm64/include/asm/nmi.h | 24 +++++++
arch/arm64/kernel/smp.c | 109 +++++++++++++++++++++-----------
drivers/firmware/Kconfig | 2 +
drivers/firmware/arm_sdei_nmi.c | 75 ++++++++++++++++++++++
4 files changed, 172 insertions(+), 38 deletions(-)
diff --git a/arch/arm64/include/asm/nmi.h b/arch/arm64/include/asm/nmi.h
index 9366be419d18..2e8974ff8d63 100644
--- a/arch/arm64/include/asm/nmi.h
+++ b/arch/arm64/include/asm/nmi.h
@@ -4,21 +4,45 @@
#include <linux/cpumask.h>
+struct pt_regs;
+
/*
* Cross-CPU NMI provider hooks, consulted by the arm64 arch code before
* its regular-IRQ / pseudo-NMI IPI paths. The SDEI provider in
* drivers/firmware/arm_sdei_nmi.c implements them when active; a future
* FEAT_NMI provider could slot in here too. The stubs let callers stay
* unconditional when ARM_SDEI_NMI is off.
+ *
+ * sdei_nmi_active() lets a caller test for the service before committing
+ * to (and waiting on) the SDEI stop rung; sdei_nmi_stop_cpus() then signals
+ * the targets, which ack by going offline.
*/
#ifdef CONFIG_ARM_SDEI_NMI
bool sdei_nmi_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu);
+bool sdei_nmi_active(void);
+void sdei_nmi_stop_cpus(const cpumask_t *mask);
#else
static inline bool sdei_nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
int exclude_cpu)
{
return false;
}
+
+static inline bool sdei_nmi_active(void)
+{
+ return false;
+}
+
+static inline void sdei_nmi_stop_cpus(const cpumask_t *mask) { }
#endif
+/*
+ * The common "stop this CPU" entry every arm64 stop path funnels through:
+ * the regular/pseudo-NMI stop IPI handlers, panic_smp_self_stop(), and the
+ * SDEI cross-CPU NMI handler. @die_on_crash powers the CPU off on the kdump
+ * crash path (IPI handlers) instead of parking it (SDEI / self-stop).
+ * Defined in arch/arm64/kernel/smp.c.
+ */
+void __noreturn arm64_nmi_cpu_stop(struct pt_regs *regs, bool die_on_crash);
+
#endif /* __ASM_NMI_H */
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index a670434a8cae..e85a4ba18d5c 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -33,6 +33,7 @@
#include <linux/kernel_stat.h>
#include <linux/kexec.h>
#include <linux/kgdb.h>
+#include <linux/kprobes.h>
#include <linux/kvm_host.h>
#include <linux/nmi.h>
@@ -862,14 +863,58 @@ void arch_irq_work_raise(void)
}
#endif
-static void __noreturn local_cpu_stop(unsigned int cpu)
+/*
+ * Bring the local CPU to a stop, saving its register state into the vmcore
+ * on the kdump crash path first. The single point every arm64 stop path
+ * funnels through, so the bookkeeping (mask interrupts, mark offline, mask
+ * SDEI, optionally power off) lives in one place:
+ *
+ * - the regular IPI_CPU_STOP and pseudo-NMI IPI_CPU_STOP_NMI handlers;
+ * - panic_smp_self_stop(), a CPU parking itself on a parallel panic();
+ * - the SDEI cross-CPU NMI handler (drivers/firmware/arm_sdei_nmi.c),
+ * which reaches CPUs the stop IPIs could not.
+ *
+ * @regs is the register state to record in the vmcore on a crash stop; NULL
+ * means "capture the current context". @die_on_crash decides the kdump crash
+ * path: the IPI stop handlers pass true and power the CPU off (PSCI CPU_OFF,
+ * via __cpu_try_die()) so a capture kernel can reclaim it. The SDEI handler
+ * and panic_smp_self_stop() pass false and only park. For SDEI that is
+ * required, not just conservative: it runs inside an SDEI event that is
+ * deliberately never completed (completing it has firmware resume the wedged
+ * context), and a CPU_OFF from that not-yet-completed context wedges EL3 on
+ * some firmware -- a documented follow-up. Parking also matches this path's
+ * own fallback when CPU_OFF is unavailable.
+ */
+void __noreturn arm64_nmi_cpu_stop(struct pt_regs *regs, bool die_on_crash)
{
+ unsigned int cpu = smp_processor_id();
+ bool crash = IS_ENABLED(CONFIG_KEXEC_CORE) && crash_stop;
+
+ /*
+ * Use local_daif_mask() instead of local_irq_disable() to make sure
+ * that pseudo-NMIs are disabled. The "stop" code starts with an IRQ
+ * and falls back to NMI (which might be pseudo). If the IRQ finally
+ * goes through right as we're timing out then the NMI could interrupt
+ * us. It's better to prevent the NMI and let the IRQ finish since the
+ * pt_regs will be better.
+ */
+ local_daif_mask();
+
+ if (crash)
+ crash_save_cpu(regs, cpu);
+
+ /* the ack a stop requester (e.g. smp_send_stop()) polls for */
set_cpu_online(cpu, false);
- local_daif_mask();
sdei_mask_local_cpu();
+
+ if (crash && die_on_crash)
+ __cpu_try_die(cpu);
+
+ /* just in case */
cpu_park_loop();
}
+NOKPROBE_SYMBOL(arm64_nmi_cpu_stop);
/*
* We need to implement panic_smp_self_stop() for parallel panic() calls, so
@@ -878,36 +923,7 @@ static void __noreturn local_cpu_stop(unsigned int cpu)
*/
void __noreturn panic_smp_self_stop(void)
{
- local_cpu_stop(smp_processor_id());
-}
-
-static void __noreturn ipi_cpu_crash_stop(unsigned int cpu, struct pt_regs *regs)
-{
-#ifdef CONFIG_KEXEC_CORE
- /*
- * Use local_daif_mask() instead of local_irq_disable() to make sure
- * that pseudo-NMIs are disabled. The "crash stop" code starts with
- * an IRQ and falls back to NMI (which might be pseudo). If the IRQ
- * finally goes through right as we're timing out then the NMI could
- * interrupt us. It's better to prevent the NMI and let the IRQ
- * finish since the pt_regs will be better.
- */
- local_daif_mask();
-
- crash_save_cpu(regs, cpu);
-
- set_cpu_online(cpu, false);
-
- sdei_mask_local_cpu();
-
- if (IS_ENABLED(CONFIG_HOTPLUG_CPU))
- __cpu_try_die(cpu);
-
- /* just in case */
- cpu_park_loop();
-#else
- BUG();
-#endif
+ arm64_nmi_cpu_stop(NULL, false);
}
static void arm64_send_ipi(const cpumask_t *mask, unsigned int nr)
@@ -984,12 +1000,7 @@ static void do_handle_IPI(int ipinr)
case IPI_CPU_STOP:
case IPI_CPU_STOP_NMI:
- if (IS_ENABLED(CONFIG_KEXEC_CORE) && crash_stop) {
- ipi_cpu_crash_stop(cpu, get_irq_regs());
- unreachable();
- } else {
- local_cpu_stop(cpu);
- }
+ arm64_nmi_cpu_stop(get_irq_regs(), true);
break;
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
@@ -1263,6 +1274,28 @@ void smp_send_stop(void)
udelay(1);
}
+ /*
+ * If CPUs are *still* online, try the SDEI cross-CPU NMI. Firmware
+ * delivers it regardless of the target's DAIF state, so it reaches
+ * a CPU spinning with interrupts masked, which neither rung above
+ * could (without pseudo-NMI there is no NMI rung at all). Allow
+ * 100ms: a firmware round-trip per CPU, with headroom.
+ */
+ if (num_other_online_cpus() && sdei_nmi_active()) {
+ /* re-snapshot after the rungs above took CPUs offline */
+ smp_rmb();
+ cpumask_copy(&mask, cpu_online_mask);
+ cpumask_clear_cpu(smp_processor_id(), &mask);
+
+ pr_info("SMP: retry stop with SDEI NMI for CPUs %*pbl\n",
+ cpumask_pr_args(&mask));
+
+ sdei_nmi_stop_cpus(&mask);
+ timeout = USEC_PER_MSEC * 100;
+ while (num_other_online_cpus() && timeout--)
+ udelay(1);
+ }
+
if (num_other_online_cpus()) {
smp_rmb();
cpumask_copy(&mask, cpu_online_mask);
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 6501087ff90d..ab0ee36d46e7 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -46,6 +46,8 @@ config ARM_SDEI_NMI
- arch_trigger_cpumask_backtrace() (sysrq-l, RCU stalls,
hardlockup_all_cpu_backtrace, soft-lockup secondary dumps,
hung-task auxiliary dumps)
+ - smp_send_stop() escalation (reboot/halt and the
+ panic / kdump crash stop)
The driver registers a handler for the SDEI software-signalled
event (event 0) and reaches a target CPU by signalling it with
diff --git a/drivers/firmware/arm_sdei_nmi.c b/drivers/firmware/arm_sdei_nmi.c
index a82776e7b55a..b2a69be6008f 100644
--- a/drivers/firmware/arm_sdei_nmi.c
+++ b/drivers/firmware/arm_sdei_nmi.c
@@ -29,6 +29,11 @@
* hardlockup_all_cpu_backtrace, soft-lockup/hung-task secondary
* dumps all reach interrupt-masked CPUs.
*
+ * - sdei_nmi_stop_cpus() — the last rung of smp_send_stop()'s
+ * escalation (reboot/halt and the panic/kdump crash stop alike),
+ * reaching CPUs that ignored the stop IPIs; on the kdump path the
+ * wedged context is captured into the vmcore before the CPU parks.
+ *
* Delivery uses the standard SDEI software-signalled event (event 0) and
* SDEI_EVENT_SIGNAL. We register a handler for event 0, enable it, and
* poke a target CPU with sdei_event_signal(0, mpidr): firmware makes
@@ -59,8 +64,51 @@ static bool sdei_nmi_available;
#define SDEI_NMI_EVENT 0
+/*
+ * Backtrace and stop both ride SDEI event 0. That is not a chosen economy:
+ * event 0 is the only architecturally software-signalled event -- the sole
+ * event SDEI_EVENT_SIGNAL can target at an arbitrary PE. Every other event
+ * number is a firmware/platform interrupt-bound event, not something the
+ * kernel can raise cross-CPU, so a dedicated "stop" event would need
+ * firmware to define and bind it -- exactly the firmware dependency this
+ * driver sets out to avoid.
+ *
+ * Sharing one event means the handler must tell a stop apart from a
+ * backtrace. A stop is terminal and system-wide -- sdei_nmi_stop_cpus() is
+ * only reached from smp_send_stop() (reboot/halt/panic/kdump), which never
+ * returns -- so once a stop is requested, every later event-0 fire is a
+ * stop too. A single write-once flag therefore carries as much as a
+ * per-CPU mask would: sdei_nmi_stop_cpus() sets it before signalling, and
+ * the handler reads a set flag as "stop this CPU" and a clear flag as
+ * "backtrace" (handled by nmi_cpu_backtrace(), which self-gates on the
+ * framework's backtrace mask). A backtrace fire that races in after a stop
+ * has begun just stops that CPU instead -- harmless, it is going down.
+ */
+static bool sdei_nmi_stopping;
+
static int sdei_nmi_handler(u32 event, struct pt_regs *regs, void *arg)
{
+ if (READ_ONCE(sdei_nmi_stopping)) {
+ /*
+ * Never returns, and deliberately never completes the SDEI
+ * event: SDEI_EVENT_COMPLETE has firmware restore the
+ * interrupted context, which would land the CPU back in
+ * the wedged loop (or in do_idle, which BUGs at
+ * cpuhp_report_idle_dead once it sees itself offline).
+ * Returning a modified pt_regs doesn't help --
+ * arch/arm64/kernel/sdei.c::do_sdei_event only honours a PC
+ * override via its IRQ-state heuristic and otherwise hands
+ * EL3 its own saved-context slot back.
+ *
+ * Trade-off: EL3 retains ~one saved-context slot per parked
+ * CPU until the next hardware reset (~hundreds of bytes per
+ * CPU). Recoverability is unchanged versus an IPI-stopped
+ * CPU: neither comes back without a reset.
+ */
+ arm64_nmi_cpu_stop(regs, false);
+ /* unreachable */
+ }
+
/*
* nmi_cpu_backtrace() no-ops unless this CPU's bit is set in the
* global backtrace mask (driven by nmi_trigger_cpumask_backtrace()),
@@ -115,6 +163,33 @@ bool sdei_nmi_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu)
return true;
}
+bool sdei_nmi_active(void)
+{
+ return sdei_nmi_available;
+}
+
+/*
+ * Last rung of the stop escalation in smp_send_stop() (see
+ * arch/arm64/kernel/smp.c). The caller runs the regular stop IPI (and
+ * the pseudo-NMI stop IPI, where available) first; @mask holds whatever
+ * stayed online through those -- typically CPUs wedged with interrupts
+ * masked, unreachable by an IPI. Mark the stop in progress and signal
+ * event 0 at each target; a target acks by marking itself offline, which
+ * the caller polls for. The caller has already confirmed sdei_nmi_active().
+ */
+void sdei_nmi_stop_cpus(const cpumask_t *mask)
+{
+ unsigned int cpu;
+
+ WRITE_ONCE(sdei_nmi_stopping, true);
+
+ /* Publish the flag before the SMCs make targets read it */
+ smp_wmb();
+
+ for_each_cpu(cpu, mask)
+ sdei_nmi_fire(cpu);
+}
+
/*
* device_initcall (after arch_initcall(sdei_init), so the SDEI subsystem
* is up): probe the firmware, register the event, and turn on the
--
2.54.0
^ permalink raw reply related
* [PATCH v3 2/3] drivers/firmware: add SDEI cross-CPU NMI service for arm64
From: Kiryl Shutsemau @ 2026-06-15 2:35 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, James Morse
Cc: Mark Rutland, Marc Zyngier, Doug Anderson, Petr Mladek,
Thomas Gleixner, Andrew Morton, Baoquan He, Puranjay Mohan,
Usama Arif, Breno Leitao, Julien Thierry, Lecopzer Chen,
Sumit Garg, kernel-team, kexec, linux-arm-kernel, linux-kernel,
Kiryl Shutsemau (Meta)
In-Reply-To: <cover.1781490440.git.kas@kernel.org>
From: "Kiryl Shutsemau (Meta)" <kas@kernel.org>
Deliver an NMI-like event to an interrupt-masked arm64 CPU via the
standard SDEI software-signalled event (event 0), without the pseudo-NMI
hot-path cost: register a handler for event 0 and poke a target with
sdei_event_signal(0, mpidr).
First user is arch_trigger_cpumask_backtrace() (sysrq-l, RCU stalls,
hung-task/soft-lockup dumps), which otherwise rides an IPI that can't
reach a masked CPU. Falls back to the IPI path when SDEI is absent; no
watchdog backend yet, so the stock detector is untouched.
Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
---
MAINTAINERS | 2 +-
arch/arm64/include/asm/nmi.h | 24 +++++
arch/arm64/kernel/smp.c | 11 +++
drivers/firmware/Kconfig | 19 ++++
drivers/firmware/Makefile | 1 +
drivers/firmware/arm_sdei_nmi.c | 149 ++++++++++++++++++++++++++++++++
6 files changed, 205 insertions(+), 1 deletion(-)
create mode 100644 arch/arm64/include/asm/nmi.h
create mode 100644 drivers/firmware/arm_sdei_nmi.c
diff --git a/MAINTAINERS b/MAINTAINERS
index c8d4b913f26c..b5ddfb85dce9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -24797,7 +24797,7 @@ M: James Morse <james.morse@arm.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/arm/firmware/sdei.txt
-F: drivers/firmware/arm_sdei.c
+F: drivers/firmware/arm_sdei*
F: include/linux/arm_sdei.h
F: include/uapi/linux/arm_sdei.h
diff --git a/arch/arm64/include/asm/nmi.h b/arch/arm64/include/asm/nmi.h
new file mode 100644
index 000000000000..9366be419d18
--- /dev/null
+++ b/arch/arm64/include/asm/nmi.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_NMI_H
+#define __ASM_NMI_H
+
+#include <linux/cpumask.h>
+
+/*
+ * Cross-CPU NMI provider hooks, consulted by the arm64 arch code before
+ * its regular-IRQ / pseudo-NMI IPI paths. The SDEI provider in
+ * drivers/firmware/arm_sdei_nmi.c implements them when active; a future
+ * FEAT_NMI provider could slot in here too. The stubs let callers stay
+ * unconditional when ARM_SDEI_NMI is off.
+ */
+#ifdef CONFIG_ARM_SDEI_NMI
+bool sdei_nmi_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu);
+#else
+static inline bool sdei_nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
+ int exclude_cpu)
+{
+ return false;
+}
+#endif
+
+#endif /* __ASM_NMI_H */
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 1aa324104afb..a670434a8cae 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -45,6 +45,7 @@
#include <asm/daifflags.h>
#include <asm/kvm_mmu.h>
#include <asm/mmu_context.h>
+#include <asm/nmi.h>
#include <asm/numa.h>
#include <asm/processor.h>
#include <asm/smp_plat.h>
@@ -927,6 +928,16 @@ static void arm64_backtrace_ipi(cpumask_t *mask)
void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu)
{
+ /*
+ * Prefer the SDEI cross-CPU NMI provider when active: firmware
+ * dispatches the event out of EL3 and reaches CPUs that have
+ * interrupts locally masked, without the per-IRQ-mask cost that
+ * pseudo-NMI pays for the same reach. The plain IPI path below
+ * can't reach such a CPU unless pseudo-NMI is enabled.
+ */
+ if (sdei_nmi_trigger_cpumask_backtrace(mask, exclude_cpu))
+ return;
+
/*
* NOTE: though nmi_trigger_cpumask_backtrace() has "nmi_" in the name,
* nothing about it truly needs to be implemented using an NMI, it's
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index bbd2155d8483..6501087ff90d 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -36,6 +36,25 @@ config ARM_SDE_INTERFACE
standard for registering callbacks from the platform firmware
into the OS. This is typically used to implement RAS notifications.
+config ARM_SDEI_NMI
+ bool "SDEI-based cross-CPU NMI service (arm64)"
+ depends on ARM64 && ARM_SDE_INTERFACE
+ help
+ Provides SDEI-based cross-CPU NMI delivery for hooks that need
+ to reach interrupt-masked CPUs on silicon that lacks FEAT_NMI:
+
+ - arch_trigger_cpumask_backtrace() (sysrq-l, RCU stalls,
+ hardlockup_all_cpu_backtrace, soft-lockup secondary dumps,
+ hung-task auxiliary dumps)
+
+ The driver registers a handler for the SDEI software-signalled
+ event (event 0) and reaches a target CPU by signalling it with
+ SDEI_EVENT_SIGNAL. Firmware delivers the event out of EL3
+ regardless of the target's PSTATE.DAIF -- forced delivery into a
+ CPU wedged with interrupts locally masked.
+
+ If unsure, say N.
+
config EDD
tristate "BIOS Enhanced Disk Drive calls determine boot disk"
depends on X86
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 4ddec2820c96..be46f1e1dc77 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -4,6 +4,7 @@
#
obj-$(CONFIG_ARM_SCPI_PROTOCOL) += arm_scpi.o
obj-$(CONFIG_ARM_SDE_INTERFACE) += arm_sdei.o
+obj-$(CONFIG_ARM_SDEI_NMI) += arm_sdei_nmi.o
obj-$(CONFIG_DMI) += dmi_scan.o
obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o
obj-$(CONFIG_EDD) += edd.o
diff --git a/drivers/firmware/arm_sdei_nmi.c b/drivers/firmware/arm_sdei_nmi.c
new file mode 100644
index 000000000000..a82776e7b55a
--- /dev/null
+++ b/drivers/firmware/arm_sdei_nmi.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * arm64 SDEI-based cross-CPU NMI service.
+ *
+ * Delivering an "NMI-shaped" event to an EL1 context that has locally
+ * masked interrupts, on silicon without FEAT_NMI, can be done two ways:
+ *
+ * - pseudo-NMI: mask "interrupts" via the GIC priority register
+ * (ICC_PMR_EL1) instead of PSTATE.DAIF, leaving a high-priority band
+ * deliverable. Functionally this works -- but it reimplements every
+ * local_irq_disable()/enable() and exception entry/exit as a PMR
+ * write plus synchronisation, a cost paid on that hot path forever,
+ * whether or not an NMI is ever delivered.
+ *
+ * - SDEI: leave interrupt masking as the cheap PSTATE.DAIF operation
+ * and have the firmware bounce an EL3-routed Group-0 SGI back to
+ * NS-EL1 as an event callback. The cost is a firmware round-trip,
+ * but only at the rare moment delivery is actually needed.
+ *
+ * This driver takes the second path: it keeps the IRQ-mask hot path
+ * free and pays only when it fires, which is what makes cross-CPU NMI
+ * affordable on hardware where the pseudo-NMI tax isn't, until FEAT_NMI
+ * makes NMI masking cheap in the architecture itself.
+ *
+ * Capabilities provided:
+ *
+ * - sdei_nmi_trigger_cpumask_backtrace() — override for arm64's
+ * arch_trigger_cpumask_backtrace(), so sysrq-l, RCU stall dumps,
+ * hardlockup_all_cpu_backtrace, soft-lockup/hung-task secondary
+ * dumps all reach interrupt-masked CPUs.
+ *
+ * Delivery uses the standard SDEI software-signalled event (event 0) and
+ * SDEI_EVENT_SIGNAL. We register a handler for event 0, enable it, and
+ * poke a target CPU with sdei_event_signal(0, mpidr): firmware makes
+ * event 0 pending on that PE and dispatches the handler NMI-like,
+ * regardless of the target's DAIF.
+ * Availability is simply whether event 0 registers and enables -- if SDEI
+ * and its software-signalled event are present we use it, otherwise the
+ * driver stays inert.
+ */
+
+#define pr_fmt(fmt) "sdei_nmi: " fmt
+
+#include <linux/arm_sdei.h>
+#include <linux/cpumask.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/nmi.h>
+#include <linux/printk.h>
+#include <linux/ptrace.h>
+#include <linux/smp.h>
+#include <linux/types.h>
+
+#include <asm/nmi.h>
+#include <asm/smp_plat.h>
+
+static bool sdei_nmi_available;
+
+#define SDEI_NMI_EVENT 0
+
+static int sdei_nmi_handler(u32 event, struct pt_regs *regs, void *arg)
+{
+ /*
+ * nmi_cpu_backtrace() no-ops unless this CPU's bit is set in the
+ * global backtrace mask (driven by nmi_trigger_cpumask_backtrace()),
+ * so a fire that reaches a CPU not being backtraced is harmless.
+ */
+ nmi_cpu_backtrace(regs);
+ return SDEI_EV_HANDLED;
+}
+NOKPROBE_SYMBOL(sdei_nmi_handler);
+
+static void sdei_nmi_fire(unsigned int target_cpu)
+{
+ int err = sdei_event_signal(SDEI_NMI_EVENT, cpu_logical_map(target_cpu));
+
+ if (err)
+ pr_warn("SDEI_EVENT_SIGNAL to CPU %u failed: %d\n",
+ target_cpu, err);
+}
+
+/*
+ * Raise callback for nmi_trigger_cpumask_backtrace(): signal event 0
+ * at every CPU still pending in @mask. The framework excludes the local
+ * CPU from @mask before calling us.
+ */
+static void sdei_nmi_raise_backtrace(cpumask_t *mask)
+{
+ unsigned int cpu;
+
+ for_each_cpu(cpu, mask)
+ sdei_nmi_fire(cpu);
+}
+
+/*
+ * Override hook for arch_trigger_cpumask_backtrace() (see
+ * arch/arm64/kernel/smp.c). Returns true when SDEI handled the request,
+ * which is the case whenever SDEI is active; on a false return the arch
+ * falls back to its regular-IRQ (or pseudo-NMI, if enabled) IPI.
+ *
+ * On a kernel built without paying the pseudo-NMI hot-path cost (the
+ * usual case for this driver's target), the IPI can't reach a CPU that
+ * has interrupts masked -- so the backtrace of the one CPU you care
+ * about comes back empty. SDEI is dispatched out of EL3 and lands
+ * regardless of the target's DAIF, without taxing the IRQ-mask path.
+ */
+bool sdei_nmi_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu)
+{
+ if (!sdei_nmi_available)
+ return false;
+
+ nmi_trigger_cpumask_backtrace(mask, exclude_cpu,
+ sdei_nmi_raise_backtrace);
+ return true;
+}
+
+/*
+ * device_initcall (after arch_initcall(sdei_init), so the SDEI subsystem
+ * is up): probe the firmware, register the event, and turn on the
+ * cross-CPU service. If the probe fails the driver stays inert and the
+ * override hooks decline, leaving the arch's own paths in place.
+ */
+static int __init sdei_nmi_init(void)
+{
+ int err;
+
+ err = sdei_event_register(SDEI_NMI_EVENT, sdei_nmi_handler, NULL);
+ if (err) {
+ pr_err("sdei_event_register(%u) failed: %d\n",
+ SDEI_NMI_EVENT, err);
+ return 0;
+ }
+
+ err = sdei_event_enable(SDEI_NMI_EVENT);
+ if (err) {
+ pr_err("sdei_event_enable(%u) failed: %d\n",
+ SDEI_NMI_EVENT, err);
+ sdei_event_unregister(SDEI_NMI_EVENT);
+ return 0;
+ }
+
+ sdei_nmi_available = true;
+ pr_info("using SDEI cross-CPU NMI (SDEI_EVENT_SIGNAL, event %u)\n",
+ SDEI_NMI_EVENT);
+
+ return 0;
+}
+device_initcall(sdei_nmi_init);
--
2.54.0
^ permalink raw reply related
* [PATCH v3 1/3] firmware: arm_sdei: add SDEI_EVENT_SIGNAL support
From: Kiryl Shutsemau @ 2026-06-15 2:35 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, James Morse
Cc: Mark Rutland, Marc Zyngier, Doug Anderson, Petr Mladek,
Thomas Gleixner, Andrew Morton, Baoquan He, Puranjay Mohan,
Usama Arif, Breno Leitao, Julien Thierry, Lecopzer Chen,
Sumit Garg, kernel-team, kexec, linux-arm-kernel, linux-kernel,
Kiryl Shutsemau (Meta)
In-Reply-To: <cover.1781490440.git.kas@kernel.org>
From: "Kiryl Shutsemau (Meta)" <kas@kernel.org>
Add sdei_event_signal(), a thin wrapper over the SDEI_EVENT_SIGNAL call
(DEN0054) that makes the software-signalled event (event 0) pending on a
target PE -- delivered NMI-like even when that PE has interrupts masked.
It takes no locks, so it is safe to call from NMI / crash context.
Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
---
drivers/firmware/arm_sdei.c | 12 ++++++++++++
include/linux/arm_sdei.h | 6 ++++++
include/uapi/linux/arm_sdei.h | 1 +
3 files changed, 19 insertions(+)
diff --git a/drivers/firmware/arm_sdei.c b/drivers/firmware/arm_sdei.c
index f39ed7ba3a38..e3fd604d9894 100644
--- a/drivers/firmware/arm_sdei.c
+++ b/drivers/firmware/arm_sdei.c
@@ -339,6 +339,18 @@ static void _ipi_unmask_cpu(void *ignored)
sdei_unmask_local_cpu();
}
+/*
+ * Signal the software-signalled event (event 0) to @mpidr. Does nothing
+ * but the SMC -- no locks, no event lookup -- so it is safe from NMI /
+ * crash context (e.g. the cross-CPU NMI service).
+ */
+int sdei_event_signal(u32 event_num, u64 mpidr)
+{
+ return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_SIGNAL, event_num,
+ mpidr, 0, 0, 0, NULL);
+}
+NOKPROBE_SYMBOL(sdei_event_signal);
+
static void _ipi_private_reset(void *ignored)
{
int err;
diff --git a/include/linux/arm_sdei.h b/include/linux/arm_sdei.h
index f652a5028b59..3f3ec01155e8 100644
--- a/include/linux/arm_sdei.h
+++ b/include/linux/arm_sdei.h
@@ -37,6 +37,12 @@ int sdei_event_unregister(u32 event_num);
int sdei_event_enable(u32 event_num);
int sdei_event_disable(u32 event_num);
+/*
+ * Signal the software-signalled event (event 0) to another PE, NMI-like.
+ * @mpidr is the target's MPIDR affinity.
+ */
+int sdei_event_signal(u32 event_num, u64 mpidr);
+
/* GHES register/unregister helpers */
int sdei_register_ghes(struct ghes *ghes, sdei_event_callback *normal_cb,
sdei_event_callback *critical_cb);
diff --git a/include/uapi/linux/arm_sdei.h b/include/uapi/linux/arm_sdei.h
index af0630ba5437..22eb61612673 100644
--- a/include/uapi/linux/arm_sdei.h
+++ b/include/uapi/linux/arm_sdei.h
@@ -22,6 +22,7 @@
#define SDEI_1_0_FN_SDEI_PE_UNMASK SDEI_1_0_FN(0x0C)
#define SDEI_1_0_FN_SDEI_INTERRUPT_BIND SDEI_1_0_FN(0x0D)
#define SDEI_1_0_FN_SDEI_INTERRUPT_RELEASE SDEI_1_0_FN(0x0E)
+#define SDEI_1_0_FN_SDEI_EVENT_SIGNAL SDEI_1_0_FN(0x0F)
#define SDEI_1_0_FN_SDEI_PRIVATE_RESET SDEI_1_0_FN(0x11)
#define SDEI_1_0_FN_SDEI_SHARED_RESET SDEI_1_0_FN(0x12)
--
2.54.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox