Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH v4 5/5] clk: rockchip: rk3588: add GATE_GRF clocks for I2S MCLK output to IO
From: Diederik de Haas @ 2026-06-23 13:05 UTC (permalink / raw)
  To: Daniele Briguglio, Heiko Stuebner, Michael Turquette,
	Stephen Boyd, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Diederik de Haas
  Cc: Nicolas Frattaroli, linux-clk, devicetree, linux-arm-kernel,
	linux-rockchip, linux-kernel, Ricardo Pardini
In-Reply-To: <20260623123316.4111002-1-hello@superkali.me>

On Tue Jun 23, 2026 at 2:33 PM CEST, Daniele Briguglio wrote:
>> can you check if adding CLK_IGNORE_UNUSED changes the situation for you?
>> What I assume is happening is that when the clocks were not declared they were
>> just left running, while now the kernel turns off unused (but defined) clocks.
>
> That lines up with what I see. The gates are set-to-disable and reset to
> open, so before the series the bit just kept whatever the boot firmware
> left it at.
>
> Diederik, the cleanest way to confirm is to read SOC_CON6 before Linux
> touches it, e.g. md.l 0xfd58c318 at the U-Boot prompt (bit 0 is I2S0). If
> it comes up clear there, the gate is open, and if audio then breaks once
> the kernel is up, that points at clk_disable_unused turning it off because
> nothing references it.

NanoPC-T6 LTS
U-Boot: 2026.04-00003-g723f0da896bc

The 0003 comes from me adding patches for NanoPC-T6 Plus support, but
otherwise it's plain upstream U-Boot.

=> md.l 0xfd58c318
fd58c318: 00000600 00000a00 00000000 00000000  ................
fd58c328: 00000300 00092820 0fd58c338: 00000000 00000000 00000000 00000000  ................
fd58c348: 00000000 00000000 00000000 00000000  ................c358: 00000000 00000000 00000000 00000000  ................
fd58c368: 00000000 00000000 00000008: 00000000 00000000 00001000 00000240  ............@...
fd58c388: 0000003f 0000fefe 00000000 000000000 00000000 00000000 00000000  ................
fd58c3a8: 00000000 00000000 00000000 00000000 00000000 00000000 00000000  ................
fd58c3c8: 00000000 00000000 00000000 000000000 00000000 00000000 00000000  ................
fd58c3e8: 00000000 00000000 00000000 00000000  .0000000 00000000 00000000  ................
fd58c408: 00000000 00000000 00000000 00000000  ....

I'll let interpreting it up to you.

> If that turns out to be the case, CLK_IGNORE_UNUSED on the gates is a
> reasonable way to stop the kernel from closing a gate the firmware already
> left open, for boards that would rather not switch their DTS to _TO_IO.

I'm not so sure I agree that CLK_IGNORE_UNUSED is reasonable, but I'll leave
judgement up to others. I'll do the test regardless, though.

Cheers,
  Diederik

> Where a board does reference _TO_IO the consumer holds it open anyway, so
> that path is unaffected either way.
>
> Best regards,
> Daniele


^ permalink raw reply

* Re: [PATCH v4 02/12] dt-bindings: iio: dac: ad5696: rework on power supplies
From: sashiko-bot @ 2026-06-23 13:05 UTC (permalink / raw)
  To: Rodrigo Alencar via B4 Relay; +Cc: devicetree, conor+dt, robh
In-Reply-To: <20260623-ad5686-new-features-v4-2-28962a57db0f@analog.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] Unconditionally requiring new `vdd-supply` and `vlogic-supply` properties breaks validation for existing device trees.
- [Medium] Conditionally requiring `vref-supply` for `adi,ad5696` breaks schema validation for legacy device trees that use the deprecated `vcc-supply`.
--

commit 7082ab254ab9eb0509320518d5cb786825dd6cbb
Author: Rodrigo Alencar <rodrigo.alencar@analog.com>

dt-bindings: iio: dac: ad5696: rework on power supplies

This commit updates the AD5696 DAC binding to include vdd-supply,
vlogic-supply, and vref-supply, while deprecating the misleading vcc-supply.
It also updates the required property lists and conditionally requires
vref-supply for specific variants.

> diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5696.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5696.yaml
> index cc343cdf6085a..e10f8596f9d3f 100644
> --- a/Documentation/devicetree/bindings/iio/dac/adi,ad5696.yaml
> +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5696.yaml

[ ... ]

> @@ -62,8 +75,21 @@ properties:
>  required:
>    - compatible
>    - reg
> +  - vdd-supply
> +  - vlogic-supply

[Severity: Medium]
Does unconditionally adding vdd-supply and vlogic-supply to the required
list break schema validation for existing device trees?

Legacy device trees that legitimately omitted these properties will now fail
schema validation during make dtbs_check.

>  
>  allOf:
> +  - if:
> +      properties:
> +        compatible:
> +          contains:
> +            enum:
> +              - adi,ad5693
> +              - adi,ad5694
> +              - adi,ad5696
> +    then:
> +      required:
> +        - vref-supply

[Severity: Medium]
Does conditionally requiring vref-supply for these compatible strings break
schema validation for legacy device trees that use the deprecated vcc-supply?

Since vcc-supply was valid under the previous schema, making vref-supply
strictly required here will cause validation failures for existing device
trees. Should the schema allow either vref-supply or the deprecated
vcc-supply to preserve DT ABI compatibility?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260623-ad5686-new-features-v4-0-28962a57db0f@analog.com?part=2

^ permalink raw reply

* [PATCH v2 3/3] arm64: dts: qcom: glymur-crd: Add refgen supplies for PCIe PHY on Glymur
From: Qiang Yu @ 2026-06-23 13:05 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio
  Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, Qiang Yu
In-Reply-To: <20260623-phy_refgen-v2-0-4d15983bf91d@oss.qualcomm.com>

The PCIe PHYs on Glymur require a reference voltage provided by REFGEN,
which in turn is powered by two LDOs.

Since there is no devicetree node for REFGEN, add the vdda-refgen0p9 and
vdda-refgen1p2 supplies for each PCIe PHY node.

Signed-off-by: Qiang Yu <qiang.yu@oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/glymur-crd.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/glymur-crd.dtsi b/arch/arm64/boot/dts/qcom/glymur-crd.dtsi
index e784b538f42e..bdf7db3493bd 100644
--- a/arch/arm64/boot/dts/qcom/glymur-crd.dtsi
+++ b/arch/arm64/boot/dts/qcom/glymur-crd.dtsi
@@ -454,6 +454,8 @@ &pcie3b {
 &pcie3b_phy {
 	vdda-phy-supply = <&vreg_l3c_e1_0p89>;
 	vdda-pll-supply = <&vreg_l2c_e1_1p14>;
+	vdda-refgen0p9-supply = <&vreg_l1c_e1_0p82>;
+	vdda-refgen1p2-supply = <&vreg_l4f_e1_1p08>;
 };
 
 &pcie3b_port0 {
@@ -471,6 +473,8 @@ &pcie4 {
 &pcie4_phy {
 	vdda-phy-supply = <&vreg_l1c_e1_0p82>;
 	vdda-pll-supply = <&vreg_l4f_e1_1p08>;
+	vdda-refgen0p9-supply = <&vreg_l1c_e1_0p82>;
+	vdda-refgen1p2-supply = <&vreg_l4f_e1_1p08>;
 
 	status = "okay";
 };
@@ -507,6 +511,8 @@ &pcie5 {
 &pcie5_phy {
 	vdda-phy-supply = <&vreg_l2f_e0_0p82>;
 	vdda-pll-supply = <&vreg_l4h_e0_1p2>;
+	vdda-refgen0p9-supply = <&vreg_l2f_e0_0p82>;
+	vdda-refgen1p2-supply = <&vreg_l4h_e0_1p2>;
 
 	status = "okay";
 };
@@ -528,6 +534,8 @@ &pcie6 {
 &pcie6_phy {
 	vdda-phy-supply = <&vreg_l1c_e1_0p82>;
 	vdda-pll-supply = <&vreg_l4f_e1_1p08>;
+	vdda-refgen0p9-supply = <&vreg_l1c_e1_0p82>;
+	vdda-refgen1p2-supply = <&vreg_l4f_e1_1p08>;
 
 	status = "okay";
 };

-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 2/3] phy: qcom: qmp-pcie: Add vdda-refgen supplies for Glymur
From: Qiang Yu @ 2026-06-23 13:05 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio
  Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, Qiang Yu
In-Reply-To: <20260623-phy_refgen-v2-0-4d15983bf91d@oss.qualcomm.com>

The refgen providing reference voltage for PCIe QMP PHY on Glymur requires
two power supplies independent from the PHY's core and qref rails. Add
support for vdda-refgen0p9 and vdda-refgen1p2 supplies with a dedicated
glymur_qmp_phy_vreg_l list.

Update both Gen5x4 and Gen4x2 configurations to use the new supply list.

Signed-off-by: Qiang Yu <qiang.yu@oss.qualcomm.com>
---
 drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
index d3effad7a074..08bc89ce80e1 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
@@ -3488,6 +3488,10 @@ static const char * const sm8550_qmp_phy_vreg_l[] = {
 	"vdda-phy", "vdda-pll", "vdda-qref",
 };
 
+static const char * const glymur_qmp_phy_vreg_l[] = {
+	"vdda-phy", "vdda-pll", "vdda-refgen0p9", "vdda-refgen1p2",
+};
+
 /* list of resets */
 static const char * const ipq8074_pciephy_reset_l[] = {
 	"phy", "common",
@@ -4756,8 +4760,8 @@ static const struct qmp_phy_cfg glymur_qmp_gen5x4_pciephy_cfg = {
 
 	.reset_list		= sdm845_pciephy_reset_l,
 	.num_resets		= ARRAY_SIZE(sdm845_pciephy_reset_l),
-	.vreg_list		= qmp_phy_vreg_l,
-	.num_vregs		= ARRAY_SIZE(qmp_phy_vreg_l),
+	.vreg_list		= glymur_qmp_phy_vreg_l,
+	.num_vregs		= ARRAY_SIZE(glymur_qmp_phy_vreg_l),
 
 	.regs			= pciephy_v8_50_regs_layout,
 
@@ -4772,8 +4776,8 @@ static const struct qmp_phy_cfg glymur_qmp_gen4x2_pciephy_cfg = {
 
 	.reset_list		= sdm845_pciephy_reset_l,
 	.num_resets		= ARRAY_SIZE(sdm845_pciephy_reset_l),
-	.vreg_list		= qmp_phy_vreg_l,
-	.num_vregs		= ARRAY_SIZE(qmp_phy_vreg_l),
+	.vreg_list		= glymur_qmp_phy_vreg_l,
+	.num_vregs		= ARRAY_SIZE(glymur_qmp_phy_vreg_l),
 
 	.regs			= pciephy_v8_regs_layout,
 

-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 1/3] dt-bindings: phy: sc8280xp-qmp-pcie: Add vdda-refgen supply for Glymur
From: Qiang Yu @ 2026-06-23 13:05 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio
  Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, Qiang Yu
In-Reply-To: <20260623-phy_refgen-v2-0-4d15983bf91d@oss.qualcomm.com>

The PCIe QMP PHYs require a stable reference voltage provided by REFGEN,
which in turn requires two separate LDOs to operate.

Add vdda-refgen0p9-supply and vdda-refgen1p2-supply properties. Mark them
as required for the Glymur PCIe QMP PHYs for now; other platforms having
the same requirement and can be added later.

Signed-off-by: Qiang Yu <qiang.yu@oss.qualcomm.com>
---
 .../bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml         | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml
index 108cf9dc86ea..375f5fb2111f 100644
--- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml
@@ -91,6 +91,10 @@ properties:
 
   vdda-qref-supply: true
 
+  vdda-refgen0p9-supply: true
+
+  vdda-refgen1p2-supply: true
+
   qcom,4ln-config-sel:
     description: PCIe 4-lane configuration
     $ref: /schemas/types.yaml#/definitions/phandle-array
@@ -261,6 +265,18 @@ allOf:
         "#clock-cells":
           const: 0
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,glymur-qmp-gen4x2-pcie-phy
+              - qcom,glymur-qmp-gen5x4-pcie-phy
+    then:
+      required:
+        - vdda-refgen0p9-supply
+        - vdda-refgen1p2-supply
+
 examples:
   - |
     #include <dt-bindings/clock/qcom,gcc-sc8280xp.h>

-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 0/3] phy: qcom: qmp-pcie: Add vdda-refgen supply support for Glymur
From: Qiang Yu @ 2026-06-23 13:05 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio
  Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, Qiang Yu

The PCIe QMP PHYs on Glymur require both refgen for stable reference
voltage and qref for stable reference clock. The refgen requires two power
supplies: vdda-refgen0p9 and vdda-refgen1p2.

can be extended in the future.

This series creates a Glymur-specific supply list including the refgen
supplies and updates both Gen5x4 and Gen4x2 configurations to use it.

Signed-off-by: Qiang Yu <qiang.yu@oss.qualcomm.com>

Changes in v2:
- Add dts patch in this series.
- Reword commit msg of dtbinding patch.
- Link to v1: https://lore.kernel.org/all/20260208-refgen-v1-0-87ca84fd78b3@oss.qualcomm.com/ 

---
Qiang Yu (3):
      dt-bindings: phy: sc8280xp-qmp-pcie: Add vdda-refgen supply for Glymur
      phy: qcom: qmp-pcie: Add vdda-refgen supplies for Glymur
      arm64: dts: qcom: glymur-crd: Add refgen supplies for PCIe PHY on Glymur

 .../bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml         | 16 ++++++++++++++++
 arch/arm64/boot/dts/qcom/glymur-crd.dtsi                 |  8 ++++++++
 drivers/phy/qualcomm/phy-qcom-qmp-pcie.c                 | 12 ++++++++----
 3 files changed, 32 insertions(+), 4 deletions(-)
---
base-commit: 3ce97bd3c4f18608335e709c24d6a40e7036cab8
change-id: 20260621-phy_refgen-db77317ec05a

Best regards,
--  
Qiang Yu <qiang.yu@oss.qualcomm.com>


^ permalink raw reply

* Re: [PATCH v4 5/5] clk: rockchip: rk3588: add GATE_GRF clocks for I2S MCLK output to IO
From: Daniele Briguglio @ 2026-06-23 12:33 UTC (permalink / raw)
  To: Heiko Stuebner, Michael Turquette, Stephen Boyd, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Diederik de Haas
  Cc: Nicolas Frattaroli, linux-clk, devicetree, linux-arm-kernel,
	linux-rockchip, linux-kernel, Ricardo Pardini
In-Reply-To: <2100447.PIDvDuAF1L@diego>

Hi Heiko,

> can you check if adding CLK_IGNORE_UNUSED changes the situation for you?
> What I assume is happening is that when the clocks were not declared they were
> just left running, while now the kernel turns off unused (but defined) clocks.

That lines up with what I see. The gates are set-to-disable and reset to
open, so before the series the bit just kept whatever the boot firmware
left it at.

Diederik, the cleanest way to confirm is to read SOC_CON6 before Linux
touches it, e.g. md.l 0xfd58c318 at the U-Boot prompt (bit 0 is I2S0). If
it comes up clear there, the gate is open, and if audio then breaks once
the kernel is up, that points at clk_disable_unused turning it off because
nothing references it.

If that turns out to be the case, CLK_IGNORE_UNUSED on the gates is a
reasonable way to stop the kernel from closing a gate the firmware already
left open, for boards that would rather not switch their DTS to _TO_IO.
Where a board does reference _TO_IO the consumer holds it open anyway, so
that path is unaffected either way.

Best regards,
Daniele

^ permalink raw reply

* Re: [PATCH v9 1/2] dt-bindings: i3c: Add AMD I3C master controller support
From: Pandey, Radhey Shyam @ 2026-06-23 12:57 UTC (permalink / raw)
  To: Shubham Patil, git, michal.simek, alexandre.belloni, Frank.Li,
	robh, krzk+dt, conor+dt, pgaj, wsa+renesas, tommaso.merciai.xr,
	arnd, quic_msavaliy, Shyam-sundar.S-k, sakari.ailus, billy_tsai,
	kees, gustavoars, jarkko.nikula, jorge.marques, linux-i3c,
	devicetree, linux-kernel, linux-arch, linux-hardening
  Cc: radhey.shyam.pandey, srinivas.goud, shubhrajyoti.datta,
	Manikanta Guntupalli
In-Reply-To: <20260623114417.2578189-2-shubhamsanjay.patil@amd.com>

> From: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
> 
> Add device tree binding documentation for the AMD I3C master controller
> version 1.0.
> 
> Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
> Reviewed-by: Rob Herring (Arm) <robh@kernel.org>

It's missing your SOB.

Any further SoBs (Signed-off-by:s) following the author SoB are
from people handling and transporting the patch, but were not
involved in its development.


> ---
> Changes for V9:
> None.
It's not correct - you updated maintainer section in yaml?

> 
> Changes for V8:
> None.
> 
> Changes for V7:
> Added i3c controller version details to commit description.
> 
> Changes for V6:
> Corrected the file name for $id in yaml to fix the dtschema warning.
> 
> Changes for V5:
> Renamed the xlnx,axi-i3c.yaml file into xlnx,axi-i3c-1.0.yaml.
> 
> Changes for V4:
> Added h/w documentation details.
> 
> Changes for V3:
> Updated commit description.
> Corrected the order of properties and removed resets property.
> Added compatible to required list.
> Added interrupts to example.
> 
> Changes for V2:
> Updated commit subject and description.
> Moved allOf to after required.
> Removed xlnx,num-targets property.
> ---
>   .../bindings/i3c/xlnx,axi-i3c-1.0.yaml        | 56 +++++++++++++++++++
>   1 file changed, 56 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
> 
> diff --git a/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml b/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
> new file mode 100644
> index 000000000000..75f677696f02
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
> @@ -0,0 +1,56 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/i3c/xlnx,axi-i3c-1.0.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: AMD I3C master
> +
> +maintainers:
> +  - Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
> +  - Shubham Patil <shubhamsanjay.patil@amd.com>
> +
> +description:
> +  The AXI-I3C IP is an I3C Controller with an AXI4-Lite interface, compatible
> +  with the MIPI I3C Specification v1.1.1. The design includes bidirectional I/O
> +  buffers that implement open collector drivers for the SDA and SCL signals.
> +  External pull-up resistors are required to properly hold the bus at a Logic-1
> +  level when the drivers are released.
> +
> +  For more details, please see https://docs.amd.com/r/en-US/pg439-axi-i3c
> +
> +properties:
> +  compatible:
> +    const: xlnx,axi-i3c-1.0
> +
> +  reg:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +required:
> +  - compatible
> +  - reg
> +  - clocks
> +
> +allOf:
> +  - $ref: i3c.yaml#
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +    i3c@80000000 {
> +        compatible = "xlnx,axi-i3c-1.0";
> +        reg = <0x80000000 0x10000>;
> +        clocks = <&zynqmp_clk 71>;
> +        interrupt-parent = <&imux>;
> +        interrupts = <0 89 4>;

Nit - Don't use hard-coded numbers.
> +        #address-cells = <3>;
> +        #size-cells = <0>;
> +    };
> +...


^ permalink raw reply

* Re: [PATCH] of_numa: fix return -EINVAL when numa-node-id is not found in last node
From: Rob Herring @ 2026-06-23 12:53 UTC (permalink / raw)
  To: Sang-Heon Jeon
  Cc: Saravana Kannan, Andrew Morton, Dan Williams, David Hildenbrand,
	devicetree, Mike Rapoport (Microsoft)
In-Reply-To: <CABFDxMG2ysTYPwJxg8Cq-uWxc+LZzfo_3_S8WwG2wtXMcwo9sg@mail.gmail.com>

On Tue, Jun 23, 2026 at 7:08 AM Sang-Heon Jeon <ekffu200098@gmail.com> wrote:
>
> On Tue, Jun 23, 2026 at 10:42 AM Rob Herring <robh@kernel.org> wrote:
> >
> > On Sun, Jun 21, 2026 at 11:39:18PM +0900, Sang-Heon Jeon wrote:
> > > When the numa-node-id property is not found in the last memory node,
> > > of_property_read_u32() returns -EINVAL, which then becomes the return
> > > value of of_numa_parse_memory_nodes(), even though earlier memory nodes
> > > were parsed successfully.
> > >
> > > Commit 7e488677a54a ("of, numa: return -EINVAL when no numa-node-id is
> > > found") meant -EINVAL to be returned only when the numa-node-id property
> > > is not found at all, not when it is found in an earlier memory node but
> > > not in the last.
> > >
> > > Check whether at least one memory node was parsed successfully, and return
> > > 0 in that case, -EINVAL otherwise, so the return value of
> > > of_property_read_u32() for the last memory node no longer corrupts the
> > > overall return value.
> >
> > IDK, it's arguable that an incomplete DT isn't valid and something we
> > need to support. Is missing numa-node-id valid or it's just better to
> > have at least partially
> > configured NUMA nodes?
>
> You're right.
>
> Since the first implementation 298535c00a2c ("of, numa: Add NUMA of
> binding implementation.") skips memory nodes without `numa-node-id`,
> I only try to fix the error case introduced by 7e488677a54a ("of,
> numa: return -EINVAL when no numa-node-id is found").
>
> IMHO, if changing the logic is acceptable, rejecting DT with an
> incomplete NUMA configuration also seems reasonable.
> We already call memblock_validate_numa_coverage() after
> of_numa_parse_memory_nodes(),
> so such an incomplete configuration would most likely fail from that
> validation anyway.
>
> So, would it be OK to reject a DT with an incomplete NUMA
> configuration? If so, I'll make a patch in that direction instead.

Reject? As in panic()? No, because why would we make a system that
boots not boot and a panic at that stage won't be seen because your
console is not up yet. If you want to add a warning that the NUMA
information is incomplete, that would be fine.

Also, are we sure it's not valid to have some memory associated with a
numa node and some that is not?

Rob

^ permalink raw reply

* Re: [PATCH v2 10/12] ARM: dts: microchip: sama7d65: add cells for temperature calibration
From: sashiko-bot @ 2026-06-23 12:42 UTC (permalink / raw)
  To: Varshini Rajendran; +Cc: robh, conor+dt, devicetree
In-Reply-To: <20260623105944.128840-11-varshini.rajendran@microchip.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] The ADC driver fails to propagate `-EPROBE_DEFER` when acquiring the NVMEM cell, leading to silent loss of the temperature channel and thermal protection.
--

commit ef1a2c61577cd00a6df4dd81d5825424af16746d
Author: Varshini Rajendran <varshini.rajendran@microchip.com>

ARM: dts: microchip: sama7d65: add cells for temperature calibration

This commit adds an NVMEM cell to the ADC node for temperature calibration
data.

> diff --git a/arch/arm/boot/dts/microchip/sama7d65.dtsi b/arch/arm/boot/dts/microchip/sama7d65.dtsi
> index 5867fda378b19..c336f863406de 100644
> --- a/arch/arm/boot/dts/microchip/sama7d65.dtsi
> +++ b/arch/arm/boot/dts/microchip/sama7d65.dtsi
> @@ -323,6 +323,8 @@ adc: adc@e1000000 {
>  			atmel,trigger-edge-type = <IRQ_TYPE_EDGE_RISING>;
>  			atmel,startup-time-ms = <4>;
>  			#io-channel-cells = <1>;
> +			nvmem-cells = <&temperature_calib>;
> +			nvmem-cell-names = "temperature_calib";

[Severity: High]
This is a pre-existing issue, but will adding these cells expose a probe
deferral issue in the ADC driver?

In drivers/iio/adc/at91-sama5d2_adc.c:at91_adc_temp_sensor_init(),
nvmem_cell_get() may return -EPROBE_DEFER:

	temp_calib = nvmem_cell_get(dev, "temperature_calib");
	if (IS_ERR(temp_calib)) {
		ret = PTR_ERR(temp_calib);
		if (ret != -ENOENT)
			dev_err(dev, "Failed to get temperature_calib cell!\n");
		return ret;
	}

However, in at91_adc_probe(), this returned error appears to be swallowed:

	ret = at91_adc_temp_sensor_init(st, &pdev->dev);
	/* Don't register temperature channel if initialization failed. */
	if (ret)
		num_channels = st->soc_info.platform->max_channels - 1;

If the NVMEM provider (OTPC) probes after the ADC driver, the ADC driver will
permanently skip registering the temperature channel instead of deferring
its probe.

Since the system's thermal zones might rely on this channel for CPU
temperature monitoring and emergency shutdown, could this lead to a silent
loss of thermal protection? 

Would it make sense to update the driver to use dev_err_probe() and properly
propagate -EPROBE_DEFER before these cells are added?

>  			status = "disabled";
>  		};

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260623105944.128840-1-varshini.rajendran@microchip.com?part=10

^ permalink raw reply

* Re: [PATCH 2/13] dt-bindings: sound: Add Qualcomm QAIF binding
From: Harendra Gautam @ 2026-06-23 12:30 UTC (permalink / raw)
  To: Rob Herring (Arm)
  Cc: Conor Dooley, Srinivas Kandagatla, Krzysztof Kozlowski,
	devicetree, linux-sound, linux-arm-msm, linux-kernel, Mark Brown,
	Liam Girdwood
In-Reply-To: <178065883033.3171433.8446753794680185025.robh@kernel.org>

On Fri, Jun 5, 2026 at 4:57 PM Rob Herring (Arm) <robh@kernel.org> wrote:
>
>
> On Fri, 05 Jun 2026 16:07:28 +0530, Harendra Gautam wrote:
> > Add a Devicetree binding for the Qualcomm Audio Interface (QAIF) CPU DAI
> > controller used on the Shikra audio platform.
> >
> > QAIF moves PCM data between system memory and external serial audio
> > interfaces through the AIF path, and between memory and the internal Bolero
> > digital codec through the CIF path. The controller needs a binding so
> > platform Devicetree files can describe its MMIO region, DMA IOMMU stream,
> > clocks, interrupt, DAI cells and per-interface AIF configuration.
> >
> > Describe the single register region, one EE interrupt, the required GCC
> > LPASS and audio core clocks, the DMA IOMMU mapping, and 'aif-interface@N'
> > child nodes used for static PCM, TDM or MI2S configuration.
> >
> > Signed-off-by: Harendra Gautam <harendra.gautam@oss.qualcomm.com>
> > ---
> >  .../devicetree/bindings/sound/qcom,qaif.yaml  | 353 ++++++++++++++++++
> >  1 file changed, 353 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/sound/qcom,qaif.yaml
> >
>
> My bot found errors running 'make dt_binding_check' on your patch:
>
> yamllint warnings/errors:
>
> dtschema/dtc warnings/errors:
> Documentation/devicetree/bindings/sound/qcom,qaif.example.dts:28:18: fatal error: dt-bindings/clock/qcom,shikra-audiocorecc.h: No such file or directory
>    28 |         #include <dt-bindings/clock/qcom,shikra-audiocorecc.h>
>       |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> compilation terminated.
> make[2]: *** [scripts/Makefile.dtbs:140: Documentation/devicetree/bindings/sound/qcom,qaif.example.dtb] Error 1
> make[2]: *** Waiting for unfinished jobs....
> make[1]: *** [/builds/robherring/dt-review-ci/linux/Makefile:1662: dt_binding_check] Error 2
> make: *** [Makefile:248: __sub-make] Error 2
>
> doc reference errors (make refcheckdocs):
>
> See https://patchwork.kernel.org/project/devicetree/patch/20260605103739.3557573-3-harendra.gautam@oss.qualcomm.com
>
> The base for the series is generally the latest rc1. A different dependency
> should be noted in *this* patch.
>
> If you already ran 'make dt_binding_check' and didn't see the above
> error(s), then make sure 'yamllint' is installed and dt-schema is up to
> date:
>
> pip3 install dtschema --upgrade
>
> Please check and re-submit after running the above command yourself. Note
> that DT_SCHEMA_FILES can be set to your schema file to speed up checking
> your schema. However, it must be unset to test all examples with your schema.
>
Thanks for pointing out and sharing the steps, the dependent changes
are also under review,
Will mark that as dependency here in the next patch.
--Harendra

^ permalink raw reply

* Re: [PATCH 2/13] dt-bindings: sound: Add Qualcomm QAIF binding
From: Harendra Gautam @ 2026-06-23 12:26 UTC (permalink / raw)
  To: Konrad Dybcio
  Cc: Srinivas Kandagatla, Mark Brown, Liam Girdwood, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, linux-sound, linux-arm-msm,
	devicetree, linux-kernel
In-Reply-To: <3da8b668-1504-450e-bde2-b383d63090a8@oss.qualcomm.com>

On Tue, Jun 9, 2026 at 3:27 PM Konrad Dybcio
<konrad.dybcio@oss.qualcomm.com> wrote:
>
> On 6/5/26 12:37 PM, Harendra Gautam wrote:
> > Add a Devicetree binding for the Qualcomm Audio Interface (QAIF) CPU DAI
> > controller used on the Shikra audio platform.
> >
> > QAIF moves PCM data between system memory and external serial audio
> > interfaces through the AIF path, and between memory and the internal Bolero
> > digital codec through the CIF path. The controller needs a binding so
> > platform Devicetree files can describe its MMIO region, DMA IOMMU stream,
> > clocks, interrupt, DAI cells and per-interface AIF configuration.
> >
> > Describe the single register region, one EE interrupt, the required GCC
> > LPASS and audio core clocks, the DMA IOMMU mapping, and 'aif-interface@N'
> > child nodes used for static PCM, TDM or MI2S configuration.
> >
> > Signed-off-by: Harendra Gautam <harendra.gautam@oss.qualcomm.com>
> > ---
>
> [...]
>
> > +  clock-names:
> > +    items:
> > +      - const: lpass_config_clk
> > +      - const: lpass_core_axim_clk
> > +      - const: aud_dma_clk
> > +      - const: aud_dma_mem_clk
> > +      - const: bus_clk
> > +      - const: aif_if0_ebit_clk
> > +      - const: aif_if0_ibit_clk
> > +      - const: aif_if1_ebit_clk
> > +      - const: aif_if1_ibit_clk
> > +      - const: aif_if2_ebit_clk
> > +      - const: aif_if2_ibit_clk
> > +      - const: aif_if3_ebit_clk
> > +      - const: aif_if3_ibit_clk
> > +      - const: ext_mclka_clk
> > +      - const: ext_mclkb_clk
>
> Drop the _clk suffix, we already know they are clocks, as they are
> listed under the clocks property
Okay, will correct.
>
> [...]
>
> > +      qcom,qaif-aif-sync-mode:
> > +        $ref: /schemas/types.yaml#/definitions/uint32
> > +        description:
> > +          Sync mode. Use QAIF_AIF_SYNC_MODE_SHORT (0) for short (pulse)
> > +          sync or QAIF_AIF_SYNC_MODE_LONG (1) for long (level) sync.
> > +      qcom,qaif-aif-sync-src:
> > +        $ref: /schemas/types.yaml#/definitions/uint32
> > +        description:
> > +          Sync source. Use QAIF_AIF_SYNC_SRC_SLAVE (0) for slave mode
> > +          or QAIF_AIF_SYNC_SRC_MASTER (1) for master mode.
>
> Should these be boolean flags then?
It should not be, the intention is to define explicitly, for better
readability I can rename these flags as EXTERNAL/INTERNAL, Please
suggest.
>
> [...]
>
> > +        #sound-dai-cells = <1>;
> > +        #address-cells = <1>;
> > +        #size-cells = <0>;
> > +        interrupts = <GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH>;
> > +        status = "okay";
>
> status is "okay" by default if unspecified
Okay, Will remove it.
>
> Konrad

^ permalink raw reply

* Re: [PATCH v2 08/12] ARM: dts: microchip: sama7d65_curiosity: Enable ADC, DVFS
From: sashiko-bot @ 2026-06-23 12:20 UTC (permalink / raw)
  To: Varshini Rajendran; +Cc: conor+dt, devicetree, robh
In-Reply-To: <20260623105944.128840-9-varshini.rajendran@microchip.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The `&adc` device tree node override is not sorted alphabetically, violating device tree formatting guidelines.
--

commit 922e23aeb754d170e8991198310689112a690505
Author: Varshini Rajendran <varshini.rajendran@microchip.com>

ARM: dts: microchip: sama7d65_curiosity: Enable ADC, DVFS

This commit adds the regulator, pinmux, and enables the ADC for the
sama7d65 curiosity board. It also adds the cpu-supply regulator for DVFS.

> diff --git a/arch/arm/boot/dts/microchip/at91-sama7d65_curiosity.dts b/arch/arm/boot/dts/microchip/at91-sama7d65_curiosity.dts
> index 927c27260b6cc..a6a44a176f565 100644
> --- a/arch/arm/boot/dts/microchip/at91-sama7d65_curiosity.dts
> +++ b/arch/arm/boot/dts/microchip/at91-sama7d65_curiosity.dts
> @@ -97,6 +97,18 @@ &can3 {
>  	status = "okay";
>  };
>  
> +&adc {

[Severity: Low]
This isn't a bug, but should the &adc node override be sorted alphabetically
within the device tree file?

It is currently inserted after &can3, but standard device tree formatting
guidelines generally require node overrides to be sorted alphabetically to
maintain readability and reduce merge conflicts. 

> +	vddana-supply = <&vddout25>;
> +	vref-supply = <&vddout25>;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_adc_default &pinctrl_adtrg_default>;
> +	status = "okay";
> +};

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260623105944.128840-1-varshini.rajendran@microchip.com?part=8

^ permalink raw reply

* Re: [PATCH 2/13] dt-bindings: sound: Add Qualcomm QAIF binding
From: Harendra Gautam @ 2026-06-23 12:17 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Mark Brown, Liam Girdwood, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, linux-sound, linux-arm-msm, devicetree,
	linux-kernel
In-Reply-To: <69d2e4a7-eb2e-42f2-83e4-0d8ca4b62da8@kernel.org>

On Wed, Jun 17, 2026 at 1:29 AM Srinivas Kandagatla <srini@kernel.org> wrote:
>
>
>
> On 6/5/26 11:37 AM, Harendra Gautam wrote:
> > Add a Devicetree binding for the Qualcomm Audio Interface (QAIF) CPU DAI
> > controller used on the Shikra audio platform.
> >
> > QAIF moves PCM data between system memory and external serial audio
> > interfaces through the AIF path, and between memory and the internal Bolero
> > digital codec through the CIF path. The controller needs a binding so
> > platform Devicetree files can describe its MMIO region, DMA IOMMU stream,
> > clocks, interrupt, DAI cells and per-interface AIF configuration.
> >
> > Describe the single register region, one EE interrupt, the required GCC
> > LPASS and audio core clocks, the DMA IOMMU mapping, and 'aif-interface@N'
> > child nodes used for static PCM, TDM or MI2S configuration.
> >
> > Signed-off-by: Harendra Gautam <harendra.gautam@oss.qualcomm.com>
> > ---
> >  .../devicetree/bindings/sound/qcom,qaif.yaml  | 353 ++++++++++++++++++
> >  1 file changed, 353 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/sound/qcom,qaif.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/sound/qcom,qaif.yaml b/Documentation/devicetree/bindings/sound/qcom,qaif.yaml
>
> Pl run dt-bindings checks before posting.
> > new file mode 100644
> > index 000000000000..5b385e05a650
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/sound/qcom,qaif.yaml
> > @@ -0,0 +1,361 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/sound/qcom,qaif.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Qualcomm Audio Interface (QAIF) CPU DAI Controller
> > +
> > +maintainers:
> > +  - Harendra Gautam <harendra.gautam@oss.qualcomm.com>
> > +
> > +description:
> > +  |
> > +  The Qualcomm Audio Interface (QAIF) is a fully configurable DMA-based
> > +  audio subsystem controller. It serialises and deserialises PCM audio
> > +  between system memory and external serial audio peripherals (PCM, TDM,
> > +  I2S, MI2S) through the AIF path, and transfers parallel audio between
> > +  memory and an internal WCD codec through the CIF path.
> > +
> > +  AIF (Audio Interface): up to 13 multi-lane Unified Audio Interfaces,
> > +  each supporting up to 8 independent data lanes. Each lane is individually
> > +  configurable as TX (output/speaker) or RX (input/mic). All lanes of an
> > +  interface share a single bit clock and frame sync. Supported modes are
> > +  PCM (short/long sync), TDM, and MI2S (stereo/mono). Per-interface
> > +  configuration includes sync source (master/slave), sync mode, sync delay,
> > +  sync inversion, slot width (8/16/24/32-bit), sample width, active slot
> > +  masks (up to 32 slots), bits-per-lane frame size, lane enable/direction
> > +  masks, loopback, output-enable control, and full-cycle path support for
> > +  long chip-to-chip connections.
> > +
> > +  CIF (Codec Interface): up to 32 RDDMA (playback) and 32 WRDMA (capture)
> > +  channels connecting to an internal codec over a parallel bus. Each channel
> > +  supports active-channel enable mask (up to 16 channels), frame-sync
> > +  selection, frame-sync delay, frame-sync output gating, dynamic clock
> > +  gating, and 16-bit packing/unpacking.
> > +
> > +  Note on RX/TX naming convention: in QAIF, RX refers to the capture path
> > +  (audio received from the interface into memory) and TX refers to the
> > +  playback path (audio transmitted from memory to the interface). This
> > +  applies to both AIF lane directions and CIF slot/mask properties.
> > +
> > +  DMA engine: RDDMA fetches audio from DDR/TCM/LPM into a shared SRAM
> > +  latency buffer (SHRAM) and drains it to the interface. WRDMA collects
> > +  data from the interface into SHRAM and writes it to memory. Each DMA
> > +  owns a private SHRAM region defined by start address and length registers.
> > +  Burst sizes of 1/2/4/8/16 beats (64-bit) are supported with up to 4
> > +  outstanding transactions per DMA. Two QSB master ports (QXM0 for TCM,
> > +  QXM1 for DDR/LPM) provide the memory interface.
> > +
> > +  Resources are partitioned among up to 5 Execution Engines (EEs) via
> > +  EE map registers. Each EE owns a set of DMAs, audio interfaces, and
> > +  interface groups, and receives its own independent interrupt output.
> > +  The interrupt hierarchy has a two-level structure: a summary register
> > +  identifies the event class (DMA period, underflow/overflow, error
> > +  response, audio interface underflow/overflow, group done, rate detector,
> > +  VFR), and per-resource status registers identify the specific channel.
> > +
> > +  Interface grouping (bonding) allows up to 6 groups of audio and codec
> > +  interfaces to start synchronously and align their DMA period interrupts
> > +  within half a frame duration using the RDDMA padding feature.
> > +
> > +  Two rate detector blocks measure the frequency of incoming frame sync or
> > +  word select signals and generate interrupts on rate change, undetected
> > +  rate, or sync timeout.
> > +
> > +  Block diagram::
> > +
> > +    System Memory (DDR / LPM / TCM)
> > +    +---------------------------------+
> > +    |  Circular Buffers (ping-pong)   |
> > +    +----------+----------+-----------+
> > +               |          ^
> > +         64-bit AXI  64-bit AXI
> > +               |          |
> > +    +----------v----------+-----------+
> > +    |        QSB Master Ports         |
> > +    |  +----------+  +----------+     |
> > +    |  |   QXM0   |  |   QXM1   |     |
> > +    |  +----+-----+  +-----+----+     |
> > +    +-------|--------------|----------+
> > +            |              |
> > +    +-------v--------------v----------+
> > +    |         Shared RAM (SHRAM)       |
> > +    |  +------------+  +------------+ |
> > +    |  | QXM0 Read  |  | QXM0 Write | |
> > +    |  | SHRAM      |  | SHRAM      | |
> > +    |  +------------+  +------------+ |
> > +    |  +------------+  +------------+ |
> > +    |  | QXM1 Read  |  | QXM1 Write | |
> > +    |  | SHRAM      |  | SHRAM      | |
> > +    |  +------------+  +------------+ |
> > +    +---+--------+--------+-------+---+
> > +        |        |        |       |
> > +    +---v--+  +--v---+ +--v---+ +-v----+
> > +    |RDDMA |  |RDDMA | |WRDMA | |WRDMA |
> > +    | AIF  |  | CIF  | | AIF  | | CIF  |
> > +    |[0..n]|  |[0..n]| |[0..n]| |[0..n]|
> > +    +--+---+  +--+---+ +--+---+ +-+----+
> > +       |         |       ^          ^
> > +       | TX      | TX    | RX       | RX
> > +       v         v       |          |
> > +    +--+--------------------+  +----+----------+
> > +    |  Unified Audio Intf   |  | Codec DMA     |
> > +    |  (AIF 0..12)          |  | Interface     |
> > +    |                       |  | (CIF)         |
> > +    |  AUD_INTFa block:     |  |               |
> > +    |  - Serializer (TX)    |  | RDDMA: DDR -> |
> > +    |  - De-serializer (RX) |  |   internal    |
> > +    |  - Sync gen/detect    |  |   codec       |
> > +    |  - Up to 8 data lanes |  | WRDMA: codec  |
> > +    |  - PCM / TDM / MI2S   |  |   -> DDR      |
> > +    |  - Near Pad Logic     |  | Up to 16 ch   |
> > +    +--+--------------------+  +----+----------+
> > +       |  Lane 0..7 (TX/RX)       |  Parallel bus
> > +       |  Bit clk + Frame sync    |  + Frame sync
> > +       v                          v
> > +    +--+--------+          +------+------+
> > +    | External  |          | Internal    |
> > +    | Serial    |          | Digital     |
> > +    | Peripherals|         | Codec       |
> > +    | (PCM/TDM/ |          | (Bolero/    |
> > +    |  MI2S)    |          |  WCD)       |
> > +    +-----------+          +-------------+
> > +
> > +properties:
> > +  compatible:
> > +    enum:
> > +      - qcom,shikra-qaif-cpu
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  iommus:
> > +    maxItems: 1
> > +
> > +  clocks:
> > +    minItems: 15
> > +    maxItems: 15
> > +
> > +  clock-names:
> > +    items:
> > +      - const: lpass_config_clk
> > +      - const: lpass_core_axim_clk
> > +      - const: aud_dma_clk
> > +      - const: aud_dma_mem_clk
> > +      - const: bus_clk
> > +      - const: aif_if0_ebit_clk
> > +      - const: aif_if0_ibit_clk
> > +      - const: aif_if1_ebit_clk
> > +      - const: aif_if1_ibit_clk
> > +      - const: aif_if2_ebit_clk
> > +      - const: aif_if2_ibit_clk
> > +      - const: aif_if3_ebit_clk
> > +      - const: aif_if3_ibit_clk
> > +      - const: ext_mclka_clk
> > +      - const: ext_mclkb_clk
>
>
> Also do we really need to specify these 15 clocks even though I use only
> one aif interface on my board.
As an example added all supported clock in this binding, in board
specific DT required clocks can be used.
--Harendra
>
> should some of these clocks belong to each aif child node instead of
> global qaif-cpu?
some of these clocks are interface related like aif_if0_ibit, kept in
parent node by taking reference from lpass-cpu driver.
--Harendra
>
> > +
> > +  interrupts:
> > +    maxItems: 1
> > +
> > +  '#sound-dai-cells':
> > +    const: 1
> > +
> > +  '#address-cells':
> > +    const: 1
> > +
> > +  '#size-cells':
> > +    const: 0
> > +
> > +  status: true
> > +
> > +patternProperties:
> > +  "^aif-interface@[0-9a-f]+$":
> > +    type: object
> > +    description:
> > +      AIF interface configuration child node. The compatible string
> > +      identifies the serial protocol the interface is wired for on the
> > +      board. The unit address matches the hardware AIF interface index.
> > +    properties:
> > +      compatible:
> > +        enum:
> > +          - qcom,qaif-pcm-dai
> > +          - qcom,qaif-tdm-dai
> > +          - qcom,qaif-mi2s-dai
> > +      reg:
> > +        maxItems: 1
> > +        description: |
> > +          Hardware AIF interface index (AUD_INTFa block index). This value
> > +          also serves as the ALSA DAI ID; it corresponds directly to the
> > +          QAIF_MI2S_TDM_AIFn constants in <dt-bindings/sound/qcom,qaif.h>
> > +          (e.g. reg = <2> selects QAIF_MI2S_TDM_AIF2).
> > +      qcom,qaif-aif-sync-mode:
> > +        $ref: /schemas/types.yaml#/definitions/uint32
>
> These should be enum instead of uint32, simillar comments apply to some
> of the properties that have only few supported values.
Okay
>
> > +        description:
> > +          Sync mode. Use QAIF_AIF_SYNC_MODE_SHORT (0) for short (pulse)
> > +          sync or QAIF_AIF_SYNC_MODE_LONG (1) for long (level) sync.
> > +      qcom,qaif-aif-sync-src:
> > +        $ref: /schemas/types.yaml#/definitions/uint32
> > +        description:
> > +          Sync source. Use QAIF_AIF_SYNC_SRC_SLAVE (0) for slave mode
> > +          or QAIF_AIF_SYNC_SRC_MASTER (1) for master mode.
> > +      qcom,qaif-aif-invert-sync:
> > +        type: boolean
> > +        description: Invert the frame sync polarity.
> > +      qcom,qaif-aif-sync-delay:
> > +        $ref: /schemas/types.yaml#/definitions/uint32
> > +        description: Number of bit-clock cycles to delay the data relative to sync.
>
> This looks redundant to qcom,qaif-aif-sync-mode, which already indicates
> the delay information?
SYNC_MODE defines the pulse width/duration (Short/Long/One-slot),
whereas SYNC_DELAY specifies the independent cycle offset for the MSB
data start relative to the sync edge.
>
> > +      qcom,qaif-aif-slot-width-rx:
> > +        $ref: /schemas/types.yaml#/definitions/uint32
> > +        description:
> > +          RX slot width in bits. This is a board-specific hardware constraint
> > +          determined by the wiring of the serial audio interface.
> > +      qcom,qaif-aif-slot-width-tx:
> > +        $ref: /schemas/types.yaml#/definitions/uint32
> > +        description:
> > +          TX slot width in bits. This is a board-specific hardware constraint
> > +          determined by the wiring of the serial audio interface.
> > +      qcom,qaif-aif-slot-en-rx-mask:
> > +        $ref: /schemas/types.yaml#/definitions/uint32
> > +        description:
> > +          Bitmask of active RX slots. Board-specific — determined by which
> > +          TDM slots the codec is wired to on this board.
> > +      qcom,qaif-aif-slot-en-tx-mask:
> > +        $ref: /schemas/types.yaml#/definitions/uint32
> > +        description:
> > +          Bitmask of active TX slots. Board-specific — determined by which
> > +          TDM slots the codec is wired to on this board.
> > +      qcom,qaif-aif-loopback:
> > +        type: boolean
> > +        description: Enable loopback mode (presence enables loopback).
>
> What is this mode used for, testing ?
this is used to test/validate DMA and interface level loopback with QAIF IP.
>
> > +      qcom,qaif-aif-ctrl-data-oe:
> > +        type: boolean
> > +        description: Enable output drive on the control/data line.
>
> will this be ever false?
Yes, as per HPG whenever there is point to point connection this has
to be false.
>
> > +      qcom,qaif-aif-lane-config:
> > +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
> > +        description:
> > +          Lane configuration matrix. Each row is a pair <enable direction>
> > +          for one lane starting from lane 0, up to 8 lanes. Use
> > +          QAIF_AIF_LANE_ENABLE (1) or QAIF_AIF_LANE_DISABLE (0) for enable.
> > +          Use QAIF_AIF_LANE_DIR_TX (0) for TX (speaker) or QAIF_AIF_LANE_DIR_RX
> > +          (1) for RX (mic). TX and RX lanes should each be grouped contiguously.
> what do  you mean ? can you elobrate how can you enforce this?
intention to have matrix from DT, where each rows are Lanes and in
each row, col[0] = lane enable/disable and col[1]=spkr/mic
>
> > +        maxItems: 8
> > +        items:
> > +          items:
> > +            - description: Lane enable (0 = disabled, 1 = enabled)
> > +              enum: [0, 1]
> > +            - description: Lane direction (0 = TX/speaker, 1 = RX/mic)
> > +              enum: [0, 1]
> > +      qcom,qaif-aif-full-cycle-en:
> > +        type: boolean
> > +        description: Enable full-cycle sync (effective in sync master mode).
> > +      qcom,qaif-aif-bits-per-lane:
> > +        $ref: /schemas/types.yaml#/definitions/uint32
> > +        description:
> > +          Number of slots per lane. The frame length is computed as
>
> bits per lane?
Yes.
>
> > +          slot-width multiplied by bits-per-lane.
> > +    if:
> > +      properties:
> > +        compatible:
> > +          const: qcom,qaif-mi2s-dai
> > +    then:
> > +      description:
> > +        MI2S interface. Sync mode and slot-enable masks are fixed by the
> > +        MI2S protocol and must not be set in DT. Mono/stereo mode is
> > +        determined at runtime from the stream channel count.
> > +      properties:
> > +        qcom,qaif-aif-sync-mode: false
> > +        qcom,qaif-aif-slot-en-rx-mask: false
> > +        qcom,qaif-aif-slot-en-tx-mask: false
> > +    else:
> > +      description:
> > +        PCM or TDM interface. Sync mode and slot-enable masks are
> > +        board-specific and must be provided. Mono mode does not apply.
> > +      required:
> > +        - qcom,qaif-aif-sync-mode
> > +        - qcom,qaif-aif-slot-en-rx-mask
> > +        - qcom,qaif-aif-slot-en-tx-mask
> > +
> > +    required:
> > +      - compatible
> > +      - reg
> > +    additionalProperties: false
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - iommus
> do we
yes.
> > +  - clocks
> > +  - clock-names
> > +  - interrupts
> > +  - '#sound-dai-cells'
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    /* Shikra platform example */
> > +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> > +    #include <dt-bindings/interrupt-controller/irq.h>
> > +    #include <dt-bindings/sound/qcom,qaif.h>
> > +    #include <dt-bindings/clock/qcom,shikra-audiocorecc.h>
> > +    #include <dt-bindings/clock/qcom,gcc-shikra.h>
> > +
> > +    qaif_cpu: audio@a000000 {
> > +        compatible = "qcom,shikra-qaif-cpu";
> > +        reg = <0x0 0x0a000000 0x0 0x20000>;
> > +        iommus = <&apps_smmu 0x1c0 0x0>;
> > +        clocks = <&gcc GCC_LPASS_CONFIG_CLK>,
> > +                 <&gcc GCC_LPASS_CORE_AXIM_CLK>,
> > +                 <&audiocorecc AUDIO_CORE_CC_AUD_DMA_CLK>,
> > +                 <&audiocorecc AUDIO_CORE_CC_AUD_DMA_MEM_CLK>,
> > +                 <&audiocorecc AUDIO_CORE_CC_BUS_CLK>,
> > +                 <&audiocorecc AUDIO_CORE_CC_AIF_IF0_EBIT_CLK>,
> > +                 <&audiocorecc AUDIO_CORE_CC_AIF_IF0_IBIT_CLK>,
> > +                 <&audiocorecc AUDIO_CORE_CC_AIF_IF1_EBIT_CLK>,
> > +                 <&audiocorecc AUDIO_CORE_CC_AIF_IF1_IBIT_CLK>,
> > +                 <&audiocorecc AUDIO_CORE_CC_AIF_IF2_EBIT_CLK>,
> > +                 <&audiocorecc AUDIO_CORE_CC_AIF_IF2_IBIT_CLK>,
> > +                 <&audiocorecc AUDIO_CORE_CC_AIF_IF3_EBIT_CLK>,
> > +                 <&audiocorecc AUDIO_CORE_CC_AIF_IF3_IBIT_CLK>,
> > +                 <&audiocorecc AUDIO_CORE_CC_EXT_MCLKA_OUT_CLK>,
> > +                 <&audiocorecc AUDIO_CORE_CC_EXT_MCLKB_OUT_CLK>;
> > +        clock-names = "lpass_config_clk",
> > +                      "lpass_core_axim_clk",
> > +                      "aud_dma_clk",
> > +                      "aud_dma_mem_clk",
> > +                      "bus_clk",
> > +                      "aif_if0_ebit_clk",
> > +                      "aif_if0_ibit_clk",
> > +                      "aif_if1_ebit_clk",
> > +                      "aif_if1_ibit_clk",
> > +                      "aif_if2_ebit_clk",
> > +                      "aif_if2_ibit_clk",
> > +                      "aif_if3_ebit_clk",
> > +                      "aif_if3_ibit_clk",
> > +                      "ext_mclka_clk",
> > +                      "ext_mclkb_clk";
> > +        #sound-dai-cells = <1>;
> > +        #address-cells = <1>;
> > +        #size-cells = <0>;
> > +        interrupts = <GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH>;
> > +        status = "okay";
> > +
> > +        qaif_aif_if2: aif-interface@2 {
> > +            compatible = "qcom,qaif-tdm-dai";
> > +            reg = <QAIF_MI2S_TDM_AIF2>;
> > +            qcom,qaif-aif-sync-mode = <QAIF_AIF_SYNC_MODE_LONG>;
> > +            qcom,qaif-aif-sync-src = <QAIF_AIF_SYNC_SRC_MASTER>;
> > +            qcom,qaif-aif-sync-delay = <1>;
> > +            qcom,qaif-aif-slot-width-rx = <32>;
> > +            qcom,qaif-aif-slot-width-tx = <32>;
> > +            qcom,qaif-aif-slot-en-rx-mask = <0x3>;
> > +            qcom,qaif-aif-slot-en-tx-mask = <0x3>;
> > +            qcom,qaif-aif-ctrl-data-oe;
> > +            /* Lane 0: RX (mic); Lane 1: TX (speaker) */
> > +            qcom,qaif-aif-lane-config = <QAIF_AIF_LANE_ENABLE QAIF_AIF_LANE_DIR_RX>,
> > +                                        <QAIF_AIF_LANE_ENABLE QAIF_AIF_LANE_DIR_TX>;
> > +            /* frame length = slot-width (32) * bits-per-lane (2) = 64 bits */
> > +            qcom,qaif-aif-bits-per-lane = <2>;
> > +        };
> > +    };
>

^ permalink raw reply

* Re: [PATCH v2 07/12] ARM: dts: microchip: sama7d65: Add ADC node
From: sashiko-bot @ 2026-06-23 12:15 UTC (permalink / raw)
  To: Varshini Rajendran; +Cc: conor+dt, robh, devicetree
In-Reply-To: <20260623105944.128840-8-varshini.rajendran@microchip.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The patch introduces a new `vddout25` fixed regulator node in `sama7d65.dtsi`, but this addition is completely undocumented in the commit message, which exclusively mentions adding the ADC node.
--

commit ee5a93263289a5fcd9ba9faf0c09df7c63701b1d
Author: Varshini Rajendran <varshini.rajendran@microchip.com>

ARM: dts: microchip: sama7d65: Add ADC node

This commit adds the device tree node for the ADC controller in the
sama7d65 SoC.

> diff --git a/arch/arm/boot/dts/microchip/sama7d65.dtsi b/arch/arm/boot/dts/microchip/sama7d65.dtsi
> index 94d49e20dc794..ba775459a816e 100644
> --- a/arch/arm/boot/dts/microchip/sama7d65.dtsi
> +++ b/arch/arm/boot/dts/microchip/sama7d65.dtsi
[ ... ]
> @@ -95,6 +96,16 @@ slow_xtal: clock-slowxtal {
>  		};
>  	};
>  
> +	vddout25: fixed-regulator-vddout25 {
> +		compatible = "regulator-fixed";
> +
> +		regulator-name = "VDDOUT25";

[Severity: Medium]
Is this regulator intentionally included in this patch? The commit message
exclusively mentions adding the ADC node, but this adds a new root-level
vddout25 fixed regulator node. Should this be split into a separate commit
or documented in the commit message?

> +		regulator-min-microvolt = <2500000>;
> +		regulator-max-microvolt = <2500000>;
> +		regulator-boot-on;
> +		status = "disabled";
> +	};
> +
>  	ns_sram: sram@100000 {
[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260623105944.128840-1-varshini.rajendran@microchip.com?part=7

^ permalink raw reply

* Re: [PATCH] of_numa: fix return -EINVAL when numa-node-id is not found in last node
From: Sang-Heon Jeon @ 2026-06-23 12:08 UTC (permalink / raw)
  To: Rob Herring
  Cc: Saravana Kannan, Andrew Morton, Dan Williams, David Hildenbrand,
	devicetree, Mike Rapoport (Microsoft)
In-Reply-To: <20260623014246.GA3897146-robh@kernel.org>

On Tue, Jun 23, 2026 at 10:42 AM Rob Herring <robh@kernel.org> wrote:
>
> On Sun, Jun 21, 2026 at 11:39:18PM +0900, Sang-Heon Jeon wrote:
> > When the numa-node-id property is not found in the last memory node,
> > of_property_read_u32() returns -EINVAL, which then becomes the return
> > value of of_numa_parse_memory_nodes(), even though earlier memory nodes
> > were parsed successfully.
> >
> > Commit 7e488677a54a ("of, numa: return -EINVAL when no numa-node-id is
> > found") meant -EINVAL to be returned only when the numa-node-id property
> > is not found at all, not when it is found in an earlier memory node but
> > not in the last.
> >
> > Check whether at least one memory node was parsed successfully, and return
> > 0 in that case, -EINVAL otherwise, so the return value of
> > of_property_read_u32() for the last memory node no longer corrupts the
> > overall return value.
>
> IDK, it's arguable that an incomplete DT isn't valid and something we
> need to support. Is missing numa-node-id valid or it's just better to
> have at least partially
> configured NUMA nodes?

You're right.

Since the first implementation 298535c00a2c ("of, numa: Add NUMA of
binding implementation.") skips memory nodes without `numa-node-id`,
I only try to fix the error case introduced by 7e488677a54a ("of,
numa: return -EINVAL when no numa-node-id is found").

IMHO, if changing the logic is acceptable, rejecting DT with an
incomplete NUMA configuration also seems reasonable.
We already call memblock_validate_numa_coverage() after
of_numa_parse_memory_nodes(),
so such an incomplete configuration would most likely fail from that
validation anyway.

So, would it be OK to reject a DT with an incomplete NUMA
configuration? If so, I'll make a patch in that direction instead.

> Rob

Best Regards,
Sang-Heon Jeon

^ permalink raw reply

* Re: [PATCH v4 5/5] clk: rockchip: rk3588: add GATE_GRF clocks for I2S MCLK output to IO
From: Heiko Stübner @ 2026-06-23 12:05 UTC (permalink / raw)
  To: Daniele Briguglio, Michael Turquette, Stephen Boyd, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Diederik de Haas
  Cc: Nicolas Frattaroli, linux-clk, devicetree, linux-arm-kernel,
	linux-rockchip, linux-kernel, Ricardo Pardini
In-Reply-To: <DJGDSS875DDO.22TYPVYK5X8KZ@cknow-tech.com>

Hi Diederick,

Am Dienstag, 23. Juni 2026, 13:10:49 Mitteleuropäische Sommerzeit schrieb Diederik de Haas:
> [Resending it against v4 which wasn't present in my INBOX, but was the
> version accepted and used in my kernel]
> 
> On Tue Jun 23, 2026 at 1:08 PM CEST, Daniele Briguglio wrote:
> > The I2S MCLK outputs on RK3588 are gated by bits in the SYS_GRF
> > register SOC_CON6 (offset 0x318). These gates control whether the
> > internal CRU MCLK signals reach the external IO pins connected to
> > audio codecs.
> >
> > The kernel should explicitly manage these gates so that audio
> > functionality does not depend on bootloader register state. This is
> > analogous to what was done for RK3576 SAI MCLK outputs [1].
> >
> > Register the SYS_GRF as an auxiliary GRF with grf_type_sys using
> > rockchip_clk_add_grf(), and add GATE_GRF entries for all four I2S
> > MCLK output gates:
> >
> >   - I2S0_8CH_MCLKOUT_TO_IO (bit 0)
> >   - I2S1_8CH_MCLKOUT_TO_IO (bit 1)
> >   - I2S2_2CH_MCLKOUT_TO_IO (bit 2)
> >   - I2S3_2CH_MCLKOUT_TO_IO (bit 7)
> >
> > Board DTS files that need MCLK on an IO pin can reference these
> > clocks, e.g.:
> >
> >     clocks = <&cru I2S0_8CH_MCLKOUT_TO_IO>;
> >
> > Tested on the Youyeetoo YY3588 (RK3588) with an ES8388 codec on I2S0.
> 
> Doesn't this break audio on a lot of RK3588 based boards?
> I have a kernel with this patch set and since then analog audio on my NanoPC-T6
> LTS and my WIP NanoPC-T6 Plus stopped working.
> Until I did s/I2S0_8CH_MCLKOUT/I2S0_8CH_MCLKOUT_TO_IO/ in my dts[i] files.
> 
> And I wouldn't be surprised if the same thing applies to other RK3588 based
> boards? The same dtb file with a 7.1 kernel, without this patch set, works.

can you check if adding CLK_IGNORE_UNUSED [0] changes the situation for you?

What I assume is happening is that when the clocks were not declared they were
just left running, while now the kernel turns of unused (but defined) clocks.


[0] example in
https://elixir.bootlin.com/linux/v7.1.1/source/drivers/clk/rockchip/clk-rk3588.c#L865




^ permalink raw reply

* Re: [PATCH 3/3] backlight: lp8864: Convert from LED to backlight class driver
From: Sverdlin, Alexander @ 2026-06-23 11:59 UTC (permalink / raw)
  To: daniel@riscstar.com
  Cc: dri-devel@lists.freedesktop.org, danielt@kernel.org,
	linux-leds@vger.kernel.org, devicetree@vger.kernel.org,
	linux-fbdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <ajpw1w150SXm8Gbi@aspen.lan>

Hi Daniel,

On Tue, 2026-06-23 at 12:41 +0100, Daniel Thompson wrote:
> > The mechanism we have regarding hot plugging currently is just I2C bridge,
> > which de-registers and registers the bridged bus. So no additional drivers
> > are required, as long as I2C devices are self-contained and not glued with
> > platform devices.
> > 
> > So bottom line is, I'd prefer to just add the backlight interface to the
> > existing driver, no matter where it would live in the future.
> 
> Is there any reasion that LP8864/LP8866 is unique in appearing on a 
> hotplugged I2C bus? In other words if support for dynamism is added
> specifically to leds-lp8864.c rather than in led_bl.c then what will stop
> the same dynamic tricks from being adde to other LED drivers?

LP8864 is not special in this regard, not different from adp8860_bl.c,
adp8870_bl.c or lm3639_bl.c, which would work in my application.

So I just wanted to add currently missing backlight_device_register() to
LP8864, but there were no such dual-API drivers under drivers/leds/ that's
wht I started with moving LP8864 driver into drivers/video/backlight/.

led_bl.c however could only be hot-pluggable either if one actively
creates/destroys platform device somewhere in the code programmatically
or uses DT overlays.

Just adding backlight API to LP8864 would be much more idiomatic, I'd
say.

-- 
Alexander Sverdlin
Siemens AG
www.siemens.com

^ permalink raw reply

* Re: [PATCH v2 05/12] nvmem: microchip-otpc: add tag-based packet lookup
From: sashiko-bot @ 2026-06-23 11:58 UTC (permalink / raw)
  To: Varshini Rajendran; +Cc: conor+dt, devicetree, robh
In-Reply-To: <20260623105944.128840-6-varshini.rajendran@microchip.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Missing serialization in hardware register accesses during NVMEM read leads to data corruption on concurrent access.
--

commit 9261dabb0a9ba8aa6fc617051559e1385e26b1cc
Author: Varshini Rajendran <varshini.rajendran@microchip.com>

nvmem: microchip-otpc: add tag-based packet lookup

Add support for accessing OTP packets by their 4-byte ASCII tag while
preserving backward compatibility with the existing ID-based lookup. The
driver resolves offsets matching valid legacy selectors through ID
lookup, falling back to tag lookup for other values.

> diff --git a/drivers/nvmem/microchip-otpc.c b/drivers/nvmem/microchip-otpc.c
> index df979e8549fdb..cbb4822a97c04 100644
> --- a/drivers/nvmem/microchip-otpc.c
> +++ b/drivers/nvmem/microchip-otpc.c

[ ... ]

> @@ -154,12 +232,11 @@ static int mchp_otpc_read(void *priv, unsigned int off, void *val,
>  	int ret, payload_size;
>  
>  	/*
> -	 * We reach this point with off being multiple of stride = 4 to
> -	 * be able to cross the subsystem. Inside the driver we use continuous
> -	 * unsigned integer numbers for packet id, thus divide off by 4
> -	 * before passing it to mchp_otpc_id_to_packet().
> +	 * From this point the offset has to be translated into the actual
> +	 * packet. For this we traverse the table of contents stored in a list
> +	 * "packet" based on the access type - packet id or tag.
>  	 */
> -	packet = mchp_otpc_id_to_packet(otpc, off / 4);
> +	packet = mchp_otpc_resolve_packet(otpc, off);

[Severity: High]
This is a pre-existing issue, but does mchp_otpc_read() need serialization to
prevent concurrent hardware register accesses?

Since the NVMEM core does not serialize reg_read callbacks, multiple threads
reading the NVMEM device simultaneously could interleave hardware register
manipulations.

If mchp_otpc_read() loops over mchp_otpc_prepare_read() concurrently:

Thread A:
    writel_relaxed(tmp, otpc->base + MCHP_OTPC_MR); // Sets address

Thread B:
    writel_relaxed(tmp, otpc->base + MCHP_OTPC_MR); // Overwrites address

Could Thread B overwrite the address Thread A just wrote before Thread A
sets MCHP_OTPC_CR_READ? Both threads would then poll the same status register
and consume from the same data registers, which could lead to corrupted
payloads or invalid hardware state.

>  	if (!packet)
>  		return -EINVAL;
>  	offset = packet->offset;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260623105944.128840-1-varshini.rajendran@microchip.com?part=5

^ permalink raw reply

* Re: [PATCH v9 2/2] i3c: master: Add driver for AMD AXI I3C master controller
From: sashiko-bot @ 2026-06-23 11:57 UTC (permalink / raw)
  To: Shubham Patil; +Cc: linux-i3c, devicetree, Frank.Li, conor+dt, robh
In-Reply-To: <20260623114417.2578189-3-shubhamsanjay.patil@amd.com>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] The driver incorrectly calculates `actual_len` for early-terminated read transfers, over-reporting received bytes and exposing padding data.
- [Medium] Mixing goto-based error handling with scope-based cleanup (__free) in the same function.
- [Medium] Zero-length I2C/I3C transfers with NULL buffers are incorrectly rejected with -EINVAL.
- [Medium] Reaching DAA limits (maximum devices or exhausted dynamic addresses) causes the driver to discard all successfully enumerated devices.
--

commit 31faf134bb0fbc7c1ffe6801a15207207118c870
Author: Manikanta Guntupalli <manikanta.guntupalli@amd.com>

i3c: master: Add driver for AMD AXI I3C master controller

Add an I3C master driver and maintainers fragment for the AMD I3C bus
controller.

> diff --git a/drivers/i3c/master/amd-i3c-master.c b/drivers/i3c/master/amd-i3c-master.c
> new file mode 100644
> index 0000000000000..34ab1028c3ce8
> --- /dev/null
> +++ b/drivers/i3c/master/amd-i3c-master.c
[ ... ]
> +static void xi3c_master_rd_from_rx_fifo(struct xi3c_master *master,
> +					struct xi3c_cmd *cmd)
> +{
> +	u16 rx_data_available;
> +	u16 copy_len;
> +	u16 len;
> +
> +	rx_data_available = xi3c_rd_fifo_level(master);
> +	len = rx_data_available * XI3C_WORD_LEN;
> +
> +	if (!len)
> +		return;
> +
> +	copy_len = min_t(u16, len, cmd->rx_len);
> +	xi3c_readl_fifo(master->membase + XI3C_RD_FIFO_OFFSET,
> +			(u8 *)cmd->rx_buf, copy_len);
> +
> +	cmd->rx_buf = (u8 *)cmd->rx_buf + copy_len;
> +	cmd->rx_len -= copy_len;

[Severity: High]
Does this logic correctly account for early-terminated read transfers?

If an I3C target terminates a read early with a non-word-aligned byte count,
the hardware RX FIFO might indicate a word is available, but padding bytes
are included. This driver reads the full word and decrements rx_len. Later
in xi3c_master_i3c_xfers(), actual_len is calculated from this modified
rx_len, which could over-report the received bytes and expose padding data
to upper layers.

> +}
> +
> +static int xi3c_master_read(struct xi3c_master *master, struct xi3c_cmd *cmd)
> +{
> +	unsigned long timeout;
> +	u32 status_reg;
> +	int ret;
> +
> +	if (!cmd->rx_buf || cmd->rx_len > XI3C_MAXDATA_LENGTH)
> +		return -EINVAL;

[Severity: Medium]
Will this fail on valid zero-length transfers? Zero-length reads, such as
standard SMBus Quick commands or i2cdetect scans, typically have rx_len = 0
and a NULL rx_buf. The check here would incorrectly reject them.

[ ... ]
> +static int xi3c_master_write(struct xi3c_master *master, struct xi3c_cmd *cmd)
> +{
> +	unsigned long timeout;
> +	u16 cmd_len;
> +
> +	if (!cmd->tx_buf || cmd->tx_len > XI3C_MAXDATA_LENGTH)
> +		return -EINVAL;

[Severity: Medium]
Similarly, does this incorrectly reject valid zero-length writes with a NULL
tx_buf?

[ ... ]
> +static int xi3c_master_do_daa(struct i3c_master_controller *m)
> +{
> +	u8 pid_bufs[XI3C_MAX_DEVS][XI3C_DAA_SLAVEINFO_READ_BYTECOUNT] = {};
> +	struct xi3c_master *master = to_xi3c_master(m);
> +	struct xi3c_xfer *xfer __free(kfree) = NULL;

[Severity: Medium]
Is it safe to mix __free() scope-based cleanup with goto-based error handling
in this function?

There are explicit kernel guidelines against combining goto-based error
handling with __free() scope-based resource management in the same function,
as it can lead to fragile and confusing execution flow.

[ ... ]
> +	while (true) {
> +		struct xi3c_cmd *cmd = &xfer->cmds[0];
> +		u8 daa_byte;
> +
> +		if (master->daa.index >= XI3C_MAX_DEVS) {
> +			ret = -ENOSPC;
> +			goto err_daa;
> +		}
> +
> +		addr = i3c_master_get_free_addr(m, last_addr + 1);
> +		if (addr < 0) {
> +			ret = addr;
> +			goto err_daa;
> +		}

[Severity: Medium]
If the bus reaches the maximum device count or runs out of free dynamic
addresses, jumping to err_daa will abort the enumeration process without
registering any devices that were successfully enumerated prior to this.

Is it intended to discard the earlier successfully assigned devices instead
of keeping them?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260623114417.2578189-1-shubhamsanjay.patil@amd.com?part=2

^ permalink raw reply

* Re: [PATCH] arm64: dts: qcom: eliza: Fix disp_cc_mdss_mdp_clk_src RCG stall on Eliza EVK
From: Krzysztof Kozlowski @ 2026-06-23 11:56 UTC (permalink / raw)
  To: Konrad Dybcio, Bjorn Andersson, Konrad Dybcio, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, linux-arm-msm, devicetree,
	linux-kernel
In-Reply-To: <3d24b1bc-baca-417a-8f60-a060cab5719a@oss.qualcomm.com>

On 23/06/2026 13:43, Konrad Dybcio wrote:
> 
>> My warning probably can be fixed same way as:
>> https://lore.kernel.org/all/20260622-sm8450-qol-v1-1-37e2ee8df9da@proton.me/
> 
> Quite possibly. IIRC Mike Tipton wasn't a huge fan of park-at-init
> to begin with.
> 

I just checked and it helps here, so lets abandon this patch.

Best regards,
Krzysztof

^ permalink raw reply

* Re: [PATCH 2/2] dt-bindings: Drop incorrect usage of double '::'
From: Daniel Lezcano @ 2026-06-23 11:45 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Bjorn Andersson, Konrad Dybcio, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter Griffin, Alim Akhtar,
	Michael Turquette, Stephen Boyd, Brian Masney, Sylwester Nawrocki,
	Chanwoo Choi, Sam Protsenko, Rob Clark, Dmitry Baryshkov,
	Abhinav Kumar, Jessica Zhang, Sean Paul, Marijn Suijten,
	David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Inki Dae, Seung-Woo Kim, Kyungmin Park,
	Andi Shyti, Georgi Djakov, Lee Jones, Pavel Machek, Hans Verkuil,
	Mauro Carvalho Chehab, Ulf Hansson, Peter Rosin, Vinod Koul,
	Neil Armstrong, Linus Walleij, Geert Uytterhoeven, Magnus Damm,
	Sebastian Reichel, Javier Martinez Canillas, Liam Girdwood,
	Mark Brown, Greg Kroah-Hartman, Jiri Slaby, Srinivas Kandagatla,
	Bartlomiej Zolnierkiewicz, Rafael J. Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba, Jonathan Marek, Taniya Das, Robert Marko,
	Christian Marangi, Stephan Gerhold, Adam Skladowski,
	Sireesh Kodali, Barnabas Czeman, Imran Shaik,
	Sricharan Ramabadhran, Anusha Rao, Luo Jie, Tomasz Figa,
	Chanho Park, Sunyeal Hong, Shin Son, Krishna Manikandan,
	Jacek Anaszewski, Jaehoon Chung, Marek Szyprowski, Alina Yu,
	Andy Gross, Niklas Söderlund, Wesley Cheng, linux-arm-msm,
	devicetree, linux-kernel, linux-arm-kernel, linux-samsung-soc,
	linux-clk, dri-devel, freedreno, linux-i2c, linux-pm, linux-leds,
	linux-media, linux-mmc, linux-phy, linux-gpio, linux-renesas-soc,
	linux-serial, linux-sound, linux-usb
In-Reply-To: <20260622101606.485961-4-krzysztof.kozlowski@oss.qualcomm.com>

On 6/22/26 12:16, Krzysztof Kozlowski wrote:
> There is no use of double colon '::' in YAML. OTOH, the literal style
> block, e.g. using '|' treats all characters as content [1] therefore
> single use of ':' in descriptions is perfectly fine, whenever '|' is
> used.
> 
> Cleanup existing code, so the confusing style won't be re-used in new
> contributions.
> 
> Link: https://yaml.org/spec/1.2.2/#literal-style [1]
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
> 
> ---
> 
> Intention for this patch is to go via Rob's tree.
> ---
>   .../devicetree/bindings/arm/qcom-soc.yaml     |  4 ++--
>   .../devicetree/bindings/arm/qcom.yaml         |  4 ++--
>   .../bindings/arm/samsung/samsung-soc.yaml     |  4 ++--
>   .../display/msm/dsi-controller-main.yaml      | 20 +++++++++----------
>   .../display/samsung/samsung,fimd.yaml         |  4 ++--
>   .../bindings/i2c/samsung,s3c2410-i2c.yaml     |  2 +-
>   .../interconnect/qcom,msm8998-bwmon.yaml      |  2 +-
>   .../interconnect/samsung,exynos-bus.yaml      | 14 ++++++-------
>   .../bindings/leds/qcom,pm8058-led.yaml        |  4 ++--
>   .../bindings/leds/skyworks,aat1290.yaml       |  6 +++---
>   .../bindings/media/cec/cec-gpio.yaml          |  2 +-
>   .../bindings/mmc/samsung,exynos-dw-mshc.yaml  |  2 +-
>   .../devicetree/bindings/mux/mux-consumer.yaml |  4 ++--
>   .../bindings/phy/samsung,mipi-video-phy.yaml  |  4 ++--
>   .../bindings/phy/samsung,usb2-phy.yaml        |  2 +-
>   .../bindings/phy/samsung,usb3-drd-phy.yaml    |  2 +-
>   .../bindings/pinctrl/samsung,pinctrl.yaml     |  2 +-
>   .../bindings/power/renesas,rcar-sysc.yaml     |  2 +-
>   .../bindings/power/reset/restart-handler.yaml |  8 ++++----
>   .../bindings/regulator/maxim,max77802.yaml    |  4 ++--
>   .../bindings/regulator/richtek,rtq2208.yaml   |  2 +-
>   .../bindings/serial/qcom,msm-uartdm.yaml      |  2 +-
>   .../devicetree/bindings/slimbus/slimbus.yaml  |  4 ++--
>   .../bindings/soc/qcom/qcom,apr-services.yaml  |  2 +-
>   .../bindings/soc/qcom/qcom,rpmh-rsc.yaml      |  8 ++++----
>   .../bindings/soc/qcom/qcom,wcnss.yaml         |  2 +-
>   .../bindings/soc/renesas/renesas-soc.yaml     |  4 ++--
>   .../bindings/sound/qcom,q6asm-dais.yaml       |  2 +-
>   .../thermal/samsung,exynos-thermal.yaml       |  4 ++--

Acked-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com> # thermal


^ permalink raw reply

* [PATCH v9 2/2] i3c: master: Add driver for AMD AXI I3C master controller
From: Shubham Patil @ 2026-06-23 11:44 UTC (permalink / raw)
  To: git, michal.simek, alexandre.belloni, Frank.Li, robh, krzk+dt,
	conor+dt, pgaj, wsa+renesas, tommaso.merciai.xr, arnd,
	quic_msavaliy, Shyam-sundar.S-k, sakari.ailus, billy_tsai, kees,
	gustavoars, jarkko.nikula, jorge.marques, linux-i3c, devicetree,
	linux-kernel, linux-arch, linux-hardening
  Cc: radhey.shyam.pandey, srinivas.goud, shubhrajyoti.datta,
	shubhamsanjay.patil, Manikanta Guntupalli
In-Reply-To: <20260623114417.2578189-1-shubhamsanjay.patil@amd.com>

From: Manikanta Guntupalli <manikanta.guntupalli@amd.com>

Add an I3C master driver and maintainers fragment for the AMD I3C bus
controller.

The driver currently supports the I3C bus operating in SDR mode,
with features including Dynamic Address Assignment, private data
transfers, and CCC transfers in both broadcast and direct modes. It
also supports operation in I2C mode.

The controller's data FIFOs are accessed big-endian; the driver performs
this conversion locally using ioread32be()/iowrite32be() with the
helpers, so it does not depend on any core FIFO-endianness helpers.

Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
Co-developed-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
Co-developed-by: Shubham Patil <shubhamsanjay.patil@amd.com>
Signed-off-by: Shubham Patil <shubhamsanjay.patil@amd.com>
---
Changes for V9:
Updated commit description to note that the driver performs big-endian
FIFO accesses locally (the v8 core-helper patches were dropped).
Dropped the big-endian MMIO infrastructure patches from the series
("asm-generic/io.h: Add big-endian MMIO accessors", "i3c: fix
big-endian FIFO transfers", and "i3c: master: Add endianness support
for i3c_readl_fifo()/i3c_writel_fifo()"). The driver now performs
big-endian FIFO accesses locally using ioread32be()/iowrite32be() with
get_unaligned()/put_unaligned(), so the series is self-contained and no
longer includes internals.h.
Replaced the async completion/transfer-queue machinery with a simple
synchronous transfer path under the existing mutex.
Reworked response handling: added enum i3c_error_code to struct
xi3c_cmd, named the response codes, return -ENODEV/-EIO as appropriate
and set err = I3C_ERROR_M2/M0 so the i3c core and callers can tell a
NACK apart from a bus error; propagate err to CCC commands and to each
priv xfer (including actual_len).
Switched from .priv_xfers to the new .i3c_xfers op; reject non-SDR
modes with -EOPNOTSUPP and report actual_len.
Reworked DAA: assign addresses incrementally, bound the device count
(-ENOSPC), detect end-of-enumeration via -ENODEV, zero-initialize the
PID buffers, and check i3c_master_add_i3c_dev_locked().
Avoid busy-spinning: sleep with usleep_range() in the FIFO drain/fill
loops.
Use FIELD_PREP() with named command-FIFO field masks instead of
open-coded shifts, and convert the register-accessor macros to inline
functions.
Split the overloaded timeout macro into XI3C_RESP_TIMEOUT_US and
XI3C_XFER_TIMEOUT_MS with documented units, and add
XI3C_POLL_INTERVAL_US.
xi3c_clk_cfg(): use NSEC_PER_SEC and named timing constants, guard
against unsigned underflow, and handle I3C_BUS_MODE_MIXED_SLOW.
Dropped ENTHDR from supports_ccc_cmd() (SDR-only), and dispatch CCCs
using the I3C_CCC_DIRECT bit.
Use const for TX buffers and drop the related casts; use parity8() for
the DAA parity bit.
Updated MODULE_DESCRIPTION and authors, the copyright year, renamed the
Kconfig symbol to AMD_AXI_I3C_MASTER, and fixed the MAINTAINERS entry
(title, mailing list, and the correct binding filename).

Changes for V8:
Used time_left instead of timeout.
Used __free(kfree) for xfer to simplify err path in multiple places.

Changes for V7:
Updated timeout macro name.
Updated xi3c_master_wr_to_tx_fifo() and xi3c_master_rd_from_rx_fifo()
to use i3c_writel_fifo() and i3c_readl_fifo().

Changes for V6:
Removed typecast for xi3c_getrevisionnumber(), xi3c_wrfifolevel(),
and xi3c_rdfifolevel().
Replaced dynamic allocation with a static variable for pid_bcr_dcr.
Fixed sparse warning in do_daa by typecasting the address parity value
to u8.
Fixed sparse warning in xi3c_master_bus_init by typecasting the pid value
to u64 in info.pid calculation.

Changes for V5:
Used GENMASK_ULL for PID mask as it's 64bit mask.

Changes for V4:
Updated timeout macros.
Removed type casting for xi3c_is_resp_available() macro.
Used ioread32() and iowrite32() instead of readl() and writel()
to keep consistency.
Read XI3C_RESET_OFFSET reg before udelay().
Removed xi3c_master_free_xfer() and directly used kfree().
Skipped checking return value of i3c_master_add_i3c_dev_locked().
Used devm_mutex_init() instead of mutex_init().

Changes for V3:
Resolved merge conflicts.

Changes for V2:
Updated commit description.
Added mixed mode support with clock configuration.
Converted smaller functions into inline functions.
Used FIELD_GET() in xi3c_get_response().
Updated xi3c_master_rd_from_rx_fifo() to use cmd->rx_buf.
Used parity8() for address parity calculation.
Added guards for locks.
Dropped num_targets and updated xi3c_master_do_daa().
Used __free(kfree) in xi3c_master_send_bdcast_ccc_cmd().
Dropped PM runtime support.
Updated xi3c_master_read() and xi3c_master_write() with
xi3c_is_resp_available() check.
Created separate functions: xi3c_master_init() and xi3c_master_reinit().
Used xi3c_master_init() in bus initialization and xi3c_master_reinit()
in error paths.
Added DAA structure to xi3c_master structure.
---
 MAINTAINERS                         |    8 +
 drivers/i3c/master/Kconfig          |   15 +
 drivers/i3c/master/Makefile         |    1 +
 drivers/i3c/master/amd-i3c-master.c | 1060 +++++++++++++++++++++++++++
 4 files changed, 1084 insertions(+)
 create mode 100644 drivers/i3c/master/amd-i3c-master.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 461a3eed6129..bfaa6999913c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1035,6 +1035,14 @@ L:	linux-sound@vger.kernel.org
 S:	Supported
 F:	sound/soc/amd/
 
+AMD AXI I3C MASTER DRIVER
+M:	Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
+M:	Shubham Patil <shubhamsanjay.patil@amd.com>
+L:	linux-i3c@lists.infradead.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
+F:	drivers/i3c/master/amd-i3c-master.c
+
 AMD AXI W1 DRIVER
 M:	Kris Chaplin <kris.chaplin@amd.com>
 R:	Thomas Delev <thomas.delev@amd.com>
diff --git a/drivers/i3c/master/Kconfig b/drivers/i3c/master/Kconfig
index 2609f2b18e0a..da96d2aaa399 100644
--- a/drivers/i3c/master/Kconfig
+++ b/drivers/i3c/master/Kconfig
@@ -86,3 +86,18 @@ config RENESAS_I3C
 
 	  This driver can also be built as a module. If so, the module will be
 	  called renesas-i3c.
+
+config AMD_AXI_I3C_MASTER
+	tristate "AMD AXI I3C Master driver"
+	depends on HAS_IOMEM
+	help
+	  Support for the AMD AXI I3C master controller, a soft IP used on
+	  AMD (Xilinx) FPGAs and adaptive SoCs with ARM or MicroBlaze
+	  processors.
+
+	  The controller currently supports Standard Data Rate (SDR) mode.
+	  Features include Dynamic Address Assignment, private transfers,
+	  and CCC transfers in both broadcast and direct modes.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called amd-i3c-master.
diff --git a/drivers/i3c/master/Makefile b/drivers/i3c/master/Makefile
index 816a227b6f7a..8d82196dcf83 100644
--- a/drivers/i3c/master/Makefile
+++ b/drivers/i3c/master/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_AST2600_I3C_MASTER)	+= ast2600-i3c-master.o
 obj-$(CONFIG_SVC_I3C_MASTER)		+= svc-i3c-master.o
 obj-$(CONFIG_MIPI_I3C_HCI)		+= mipi-i3c-hci/
 obj-$(CONFIG_RENESAS_I3C)		+= renesas-i3c.o
+obj-$(CONFIG_AMD_AXI_I3C_MASTER)	+= amd-i3c-master.o
diff --git a/drivers/i3c/master/amd-i3c-master.c b/drivers/i3c/master/amd-i3c-master.c
new file mode 100644
index 000000000000..34ab1028c3ce
--- /dev/null
+++ b/drivers/i3c/master/amd-i3c-master.c
@@ -0,0 +1,1060 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * I3C master driver for the AMD I3C controller.
+ *
+ * Copyright (C) 2026, Advanced Micro Devices, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i3c/master.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/unaligned.h>
+
+#define XI3C_VERSION_OFFSET			0x00	/* Version Register */
+#define XI3C_RESET_OFFSET			0x04	/* Soft Reset Register */
+#define XI3C_CR_OFFSET				0x08	/* Control Register */
+#define XI3C_ADDRESS_OFFSET			0x0C	/* Target Address Register */
+#define XI3C_SR_OFFSET				0x10	/* Status Register */
+#define XI3C_CMD_FIFO_OFFSET			0x20	/* I3C Command FIFO Register */
+#define XI3C_WR_FIFO_OFFSET			0x24	/* I3C Write Data FIFO Register */
+#define XI3C_RD_FIFO_OFFSET			0x28	/* I3C Read Data FIFO Register */
+#define XI3C_RESP_STATUS_FIFO_OFFSET		0x2C	/* I3C Response status FIFO Register */
+#define XI3C_FIFO_LVL_STATUS_OFFSET		0x30	/* CMD slots free | WR-FIFO free (words) */
+#define XI3C_FIFO_LVL_STATUS_1_OFFSET		0x34	/* RESP fill | RD-FIFO fill level (words) */
+#define XI3C_SCL_HIGH_TIME_OFFSET		0x38	/* I3C SCL HIGH Register */
+#define XI3C_SCL_LOW_TIME_OFFSET		0x3C	/* I3C SCL LOW Register */
+#define XI3C_SDA_HOLD_TIME_OFFSET		0x40	/* I3C SDA HOLD Register */
+#define XI3C_TSU_START_OFFSET			0x48	/* I3C START SETUP Register */
+#define XI3C_THD_START_OFFSET			0x4C	/* I3C START HOLD Register */
+#define XI3C_TSU_STOP_OFFSET			0x50	/* I3C STOP Setup Register */
+#define XI3C_OD_SCL_HIGH_TIME_OFFSET		0x54	/* I3C OD SCL HIGH Register */
+#define XI3C_OD_SCL_LOW_TIME_OFFSET		0x58	/* I3C OD SCL LOW Register */
+#define XI3C_PID0_OFFSET			0x6C	/* LSB 4 bytes of the PID */
+#define XI3C_PID1_BCR_DCR			0x70	/* MSB 2 bytes of the PID, BCR and DCR */
+
+#define XI3C_CR_EN_MASK				BIT(0)	/* Core Enable */
+#define XI3C_CR_RESUME_MASK			BIT(2)	/* Core Resume */
+#define XI3C_SR_RESP_NOT_EMPTY_MASK		BIT(4)	/* Resp Fifo not empty status mask */
+#define XI3C_RD_FIFO_NOT_EMPTY_MASK		BIT(15)	/* Read Fifo not empty status mask */
+
+#define XI3C_BCR_MASK				GENMASK(23, 16)
+#define XI3C_DCR_MASK				GENMASK(31, 24)
+#define XI3C_PID_MASK				GENMASK_ULL(63, 16)
+#define XI3C_TIMING_MASK			GENMASK(17, 0)
+#define XI3C_REV_NUM_MASK			GENMASK(15, 8)
+#define XI3C_PID1_MASK				GENMASK(15, 0)
+#define XI3C_FIFO_LEVEL_MASK			GENMASK(15, 0)
+#define XI3C_RESP_CODE_MASK			GENMASK(8, 5)
+#define XI3C_RESP_CODE_SUCCESS			0	/* Transfer completed OK */
+#define XI3C_RESP_CODE_NO_TARGET		2	/* 7E NACK: no target on bus */
+#define XI3C_RESP_CODE_NACK			3	/* Target NACK / CE2 / DAA end */
+#define XI3C_ADDR_MASK				GENMASK(6, 0)
+#define XI3C_FIFOS_RST_MASK			GENMASK(4, 1)
+
+/* Command FIFO word layout (bit ranges encoded in the GENMASK/BIT args) */
+#define XI3C_CMD_TYPE				GENMASK(3, 0)	/* command type */
+#define XI3C_CMD_TERMINATE			BIT(4)		/* terminate (last cmd of xfer) */
+#define XI3C_CMD_ADDR				GENMASK(15, 8)	/* target address << 1 | RnW */
+#define XI3C_CMD_LEN				GENMASK(27, 16)	/* payload length in bytes */
+#define XI3C_CMD_TID				GENMASK(31, 28)	/* transfer ID */
+
+#define XI3C_OD_TLOW_NS				500000
+#define XI3C_OD_THIGH_NS			41000
+#define XI3C_I2C_TCASMIN_NS			600000
+#define XI3C_TCASMIN_NS				260000
+#define XI3C_MAXDATA_LENGTH			4095
+#define XI3C_MAX_DEVS				32
+#define XI3C_DAA_SLAVEINFO_READ_BYTECOUNT	8
+
+#define XI3C_THOLD_MIN_REV0			5	/* Min SDA hold cycles, rev 0 IP */
+#define XI3C_THOLD_MIN_REV1			6	/* Min SDA hold cycles, rev >= 1 IP */
+#define XI3C_CYCLE_ADJUST			2	/* SCL/SDA pre-bias for HW pipeline */
+#define XI3C_FIFO_RESET_DELAY_US		10	/* HW settling time after FIFO reset */
+#define XI3C_POLL_INTERVAL_US			10	/* readl_poll_timeout() sleep slice */
+
+#define XI3C_I2C_MODE				0
+#define XI3C_I2C_TID				0
+#define XI3C_SDR_MODE				1
+#define XI3C_SDR_TID				1
+
+#define XI3C_WORD_LEN				4
+
+/*
+ * XI3C_RESP_TIMEOUT_US is in microseconds because it is passed as the
+ * timeout_us argument of readl_poll_timeout(). XI3C_XFER_TIMEOUT_MS is in
+ * milliseconds because it feeds msecs_to_jiffies(). Keep the two units
+ * distinct in the names so callers cannot mix them up.
+ */
+#define XI3C_RESP_TIMEOUT_US			500000
+#define XI3C_XFER_TIMEOUT_MS			1000
+
+struct xi3c_cmd {
+	const void *tx_buf;
+	void *rx_buf;
+	u16 tx_len;
+	u16 rx_len;
+	u8 addr;
+	u8 type;
+	u8 tid;
+	bool rnw;
+	bool is_daa;
+	bool continued;
+	enum i3c_error_code err;
+};
+
+struct xi3c_xfer {
+	unsigned int ncmds;
+	struct xi3c_cmd cmds[] __counted_by(ncmds);
+};
+
+/**
+ * struct xi3c_master - I3C master controller state.
+ * @base: I3C master controller embedded by the framework.
+ * @dev: Pointer to the backing device structure.
+ * @membase: Memory base of the HW registers.
+ * @pclk: Input clock driving the controller.
+ * @lock: Serializes transfers and CCC submission.
+ * @daa: ENTDAA enumeration state.
+ * @daa.addrs: Dynamic addresses assigned in enumeration order.
+ * @daa.index: Number of responders enumerated so far.
+ */
+struct xi3c_master {
+	struct i3c_master_controller base;
+	struct device *dev;
+	void __iomem *membase;
+	struct clk *pclk;
+	struct mutex lock; /* serializes transfers and CCC submission */
+	struct {
+		u8 addrs[XI3C_MAX_DEVS];
+		u8 index;
+	} daa;
+};
+
+static inline struct xi3c_master *
+to_xi3c_master(struct i3c_master_controller *master)
+{
+	return container_of(master, struct xi3c_master, base);
+}
+
+static inline u8 xi3c_get_revision_number(struct xi3c_master *master)
+{
+	return FIELD_GET(XI3C_REV_NUM_MASK,
+			 ioread32(master->membase + XI3C_VERSION_OFFSET));
+}
+
+static inline u16 xi3c_wr_fifo_level(struct xi3c_master *master)
+{
+	return ioread32(master->membase + XI3C_FIFO_LVL_STATUS_OFFSET) &
+	       XI3C_FIFO_LEVEL_MASK;
+}
+
+static inline u16 xi3c_rd_fifo_level(struct xi3c_master *master)
+{
+	return ioread32(master->membase + XI3C_FIFO_LVL_STATUS_1_OFFSET) &
+	       XI3C_FIFO_LEVEL_MASK;
+}
+
+static inline bool xi3c_is_resp_available(struct xi3c_master *master)
+{
+	return FIELD_GET(XI3C_SR_RESP_NOT_EMPTY_MASK,
+			 ioread32(master->membase + XI3C_SR_OFFSET));
+}
+
+static int xi3c_get_response(struct xi3c_master *master, struct xi3c_cmd *cmd)
+{
+	u32 response_data;
+	u32 resp_reg;
+	u8 code;
+	int ret;
+
+	ret = readl_poll_timeout(master->membase + XI3C_SR_OFFSET,
+				 resp_reg,
+				 resp_reg & XI3C_SR_RESP_NOT_EMPTY_MASK,
+				 XI3C_POLL_INTERVAL_US, XI3C_RESP_TIMEOUT_US);
+	if (ret) {
+		dev_err(master->dev, "XI3C response timeout\n");
+		return ret;
+	}
+
+	response_data = ioread32(master->membase + XI3C_RESP_STATUS_FIFO_OFFSET);
+	code = FIELD_GET(XI3C_RESP_CODE_MASK, response_data);
+
+	switch (code) {
+	case XI3C_RESP_CODE_SUCCESS:
+		cmd->err = I3C_ERROR_UNKNOWN;
+		return 0;
+	case XI3C_RESP_CODE_NO_TARGET:
+	case XI3C_RESP_CODE_NACK:
+		/*
+		 * Target did not ACK. Record it as I3C_ERROR_M2 so callers
+		 * (and the i3c core, which keys on err == I3C_ERROR_M2) can
+		 * tell a NACK apart from other failures. A normal transfer
+		 * surfaces this as -EIO per the i3c_xfer contract; the DAA
+		 * path instead expects -ENODEV as its enumeration terminator.
+		 */
+		cmd->err = I3C_ERROR_M2;
+		return cmd->is_daa ? -ENODEV : -EIO;
+	default:
+		cmd->err = I3C_ERROR_M0;
+		dev_err(master->dev, "XI3C transfer error, response code %u\n",
+			code);
+		return -EIO;
+	}
+}
+
+static inline void xi3c_writesl_be(void __iomem *addr, const void *buffer,
+				   unsigned int count)
+{
+	const u32 *buf = buffer;
+
+	while (count--)
+		iowrite32be(get_unaligned(buf++), addr);
+}
+
+static inline void xi3c_readsl_be(const void __iomem *addr, void *buffer,
+				  unsigned int count)
+{
+	u32 *buf = buffer;
+
+	while (count--)
+		put_unaligned(ioread32be(addr), buf++);
+}
+
+static inline void xi3c_writel_fifo(void __iomem *addr, const void *buf,
+				    int nbytes)
+{
+	xi3c_writesl_be(addr, buf, nbytes / 4);
+	if (nbytes & 3) {
+		u32 tmp = 0;
+
+		memcpy(&tmp, (const u8 *)buf + (nbytes & ~3), nbytes & 3);
+		xi3c_writesl_be(addr, &tmp, 1);
+	}
+}
+
+static inline void xi3c_readl_fifo(const void __iomem *addr, void *buf,
+				   int nbytes)
+{
+	xi3c_readsl_be(addr, buf, nbytes / 4);
+	if (nbytes & 3) {
+		u32 tmp;
+
+		xi3c_readsl_be(addr, &tmp, 1);
+		memcpy((u8 *)buf + (nbytes & ~3), &tmp, nbytes & 3);
+	}
+}
+
+static void xi3c_master_write_to_cmdfifo(struct xi3c_master *master,
+					 struct xi3c_cmd *cmd, u16 len)
+{
+	u32 transfer_cmd;
+	u8 addr;
+
+	addr = ((cmd->addr & XI3C_ADDR_MASK) << 1) | (u8)cmd->rnw;
+
+	transfer_cmd  = FIELD_PREP(XI3C_CMD_TYPE, cmd->type);
+	transfer_cmd |= FIELD_PREP(XI3C_CMD_TERMINATE, !cmd->continued);
+	transfer_cmd |= FIELD_PREP(XI3C_CMD_ADDR, addr);
+	transfer_cmd |= FIELD_PREP(XI3C_CMD_TID, cmd->tid);
+
+	/*
+	 * For dynamic addressing, an additional 1-byte length must be added
+	 * to the command FIFO to account for the address present in the TX FIFO
+	 */
+	if (cmd->is_daa) {
+		xi3c_writel_fifo(master->membase + XI3C_WR_FIFO_OFFSET,
+				 cmd->tx_buf, cmd->tx_len);
+
+		len++;
+	}
+
+	transfer_cmd |= FIELD_PREP(XI3C_CMD_LEN, len);
+	iowrite32(transfer_cmd, master->membase + XI3C_CMD_FIFO_OFFSET);
+}
+
+static inline void xi3c_master_enable(struct xi3c_master *master)
+{
+	iowrite32(ioread32(master->membase + XI3C_CR_OFFSET) | XI3C_CR_EN_MASK,
+		  master->membase + XI3C_CR_OFFSET);
+}
+
+static inline void xi3c_master_disable(struct xi3c_master *master)
+{
+	iowrite32(ioread32(master->membase + XI3C_CR_OFFSET) & ~XI3C_CR_EN_MASK,
+		  master->membase + XI3C_CR_OFFSET);
+}
+
+static inline void xi3c_master_resume(struct xi3c_master *master)
+{
+	iowrite32(ioread32(master->membase + XI3C_CR_OFFSET) |
+		  XI3C_CR_RESUME_MASK, master->membase + XI3C_CR_OFFSET);
+}
+
+static void xi3c_master_reset_fifos(struct xi3c_master *master)
+{
+	u32 data;
+
+	/* Assert FIFO reset. */
+	data = ioread32(master->membase + XI3C_RESET_OFFSET);
+	data |= XI3C_FIFOS_RST_MASK;
+	iowrite32(data, master->membase + XI3C_RESET_OFFSET);
+	/* Read-back flushes the posted write before the settling delay below. */
+	ioread32(master->membase + XI3C_RESET_OFFSET);
+	udelay(XI3C_FIFO_RESET_DELAY_US);
+
+	/* De-assert FIFO reset, then wait for the FIFOs to come back up. */
+	data &= ~XI3C_FIFOS_RST_MASK;
+	iowrite32(data, master->membase + XI3C_RESET_OFFSET);
+	ioread32(master->membase + XI3C_RESET_OFFSET);
+	udelay(XI3C_FIFO_RESET_DELAY_US);
+}
+
+static inline void xi3c_master_init(struct xi3c_master *master)
+{
+	/* Reset fifos */
+	xi3c_master_reset_fifos(master);
+
+	/* Enable controller */
+	xi3c_master_enable(master);
+}
+
+static inline void xi3c_master_reinit(struct xi3c_master *master)
+{
+	/* Reset fifos */
+	xi3c_master_reset_fifos(master);
+
+	/* Resume controller */
+	xi3c_master_resume(master);
+}
+
+static struct xi3c_xfer *xi3c_master_alloc_xfer(unsigned int ncmds)
+{
+	struct xi3c_xfer *xfer;
+
+	xfer = kzalloc(struct_size(xfer, cmds, ncmds), GFP_KERNEL);
+	if (!xfer)
+		return NULL;
+
+	xfer->ncmds = ncmds;
+
+	return xfer;
+}
+
+static void xi3c_master_rd_from_rx_fifo(struct xi3c_master *master,
+					struct xi3c_cmd *cmd)
+{
+	u16 rx_data_available;
+	u16 copy_len;
+	u16 len;
+
+	rx_data_available = xi3c_rd_fifo_level(master);
+	len = rx_data_available * XI3C_WORD_LEN;
+
+	if (!len)
+		return;
+
+	copy_len = min_t(u16, len, cmd->rx_len);
+	xi3c_readl_fifo(master->membase + XI3C_RD_FIFO_OFFSET,
+			(u8 *)cmd->rx_buf, copy_len);
+
+	cmd->rx_buf = (u8 *)cmd->rx_buf + copy_len;
+	cmd->rx_len -= copy_len;
+}
+
+static int xi3c_master_read(struct xi3c_master *master, struct xi3c_cmd *cmd)
+{
+	unsigned long timeout;
+	u32 status_reg;
+	int ret;
+
+	if (!cmd->rx_buf || cmd->rx_len > XI3C_MAXDATA_LENGTH)
+		return -EINVAL;
+
+	/* Fill command fifo */
+	xi3c_master_write_to_cmdfifo(master, cmd, cmd->rx_len);
+
+	if (!cmd->rx_len)
+		return 0;
+
+	ret = readl_poll_timeout(master->membase + XI3C_SR_OFFSET,
+				 status_reg,
+				 status_reg & (XI3C_RD_FIFO_NOT_EMPTY_MASK |
+					       XI3C_SR_RESP_NOT_EMPTY_MASK),
+				 XI3C_POLL_INTERVAL_US, XI3C_RESP_TIMEOUT_US);
+	if (ret) {
+		dev_err(master->dev, "XI3C read timeout\n");
+		return ret;
+	}
+
+	if (!(status_reg & XI3C_RD_FIFO_NOT_EMPTY_MASK))
+		return 0;
+
+	timeout = jiffies + msecs_to_jiffies(XI3C_XFER_TIMEOUT_MS);
+
+	/* Read data from rx fifo */
+	while (cmd->rx_len > 0 && !xi3c_is_resp_available(master)) {
+		if (time_after(jiffies, timeout)) {
+			dev_err(master->dev, "XI3C read timeout\n");
+			return -EIO;
+		}
+		xi3c_master_rd_from_rx_fifo(master, cmd);
+		usleep_range(XI3C_POLL_INTERVAL_US, 2 * XI3C_POLL_INTERVAL_US);
+	}
+
+	/* Read remaining data */
+	xi3c_master_rd_from_rx_fifo(master, cmd);
+
+	return 0;
+}
+
+static void xi3c_master_wr_to_tx_fifo(struct xi3c_master *master,
+				      struct xi3c_cmd *cmd)
+{
+	u16 wrfifo_space;
+	u16 len;
+
+	wrfifo_space = xi3c_wr_fifo_level(master);
+	if (cmd->tx_len > wrfifo_space * XI3C_WORD_LEN)
+		len = wrfifo_space * XI3C_WORD_LEN;
+	else
+		len = cmd->tx_len;
+
+	if (len) {
+		xi3c_writel_fifo(master->membase + XI3C_WR_FIFO_OFFSET, cmd->tx_buf,
+				 len);
+
+		cmd->tx_buf = (const u8 *)cmd->tx_buf + len;
+		cmd->tx_len -= len;
+	}
+}
+
+static int xi3c_master_write(struct xi3c_master *master, struct xi3c_cmd *cmd)
+{
+	unsigned long timeout;
+	u16 cmd_len;
+
+	if (!cmd->tx_buf || cmd->tx_len > XI3C_MAXDATA_LENGTH)
+		return -EINVAL;
+
+	cmd_len = cmd->tx_len;
+
+	/* Fill Tx fifo */
+	xi3c_master_wr_to_tx_fifo(master, cmd);
+
+	/* Write to command fifo */
+	xi3c_master_write_to_cmdfifo(master, cmd, cmd_len);
+
+	timeout = jiffies + msecs_to_jiffies(XI3C_XFER_TIMEOUT_MS);
+	/* Fill if any remaining data to tx fifo */
+	while (cmd->tx_len > 0 && !xi3c_is_resp_available(master)) {
+		if (time_after(jiffies, timeout)) {
+			dev_err(master->dev, "XI3C write timeout\n");
+			return -EIO;
+		}
+
+		xi3c_master_wr_to_tx_fifo(master, cmd);
+		usleep_range(XI3C_POLL_INTERVAL_US, 2 * XI3C_POLL_INTERVAL_US);
+	}
+
+	return 0;
+}
+
+static int xi3c_master_xfer(struct xi3c_master *master, struct xi3c_cmd *cmd)
+{
+	int ret;
+
+	if (cmd->rnw)
+		ret = xi3c_master_read(master, cmd);
+	else
+		ret = xi3c_master_write(master, cmd);
+
+	if (ret)
+		goto err_xfer_out;
+
+	ret = xi3c_get_response(master, cmd);
+	if (ret)
+		goto err_xfer_out;
+
+	return 0;
+
+err_xfer_out:
+	xi3c_master_reinit(master);
+	return ret;
+}
+
+static int xi3c_master_common_xfer(struct xi3c_master *master,
+				   struct xi3c_xfer *xfer)
+{
+	unsigned int i;
+	int ret;
+
+	guard(mutex)(&master->lock);
+
+	for (i = 0; i < xfer->ncmds; i++) {
+		ret = xi3c_master_xfer(master, &xfer->cmds[i]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int xi3c_master_do_daa(struct i3c_master_controller *m)
+{
+	u8 pid_bufs[XI3C_MAX_DEVS][XI3C_DAA_SLAVEINFO_READ_BYTECOUNT] = {};
+	struct xi3c_master *master = to_xi3c_master(m);
+	struct xi3c_xfer *xfer __free(kfree) = NULL;
+	struct xi3c_cmd *daa_cmd;
+	int addr, ret, i;
+	u8 last_addr = 0;
+	u8 *pid_buf;
+	u8 ccc_id;
+
+	xfer = xi3c_master_alloc_xfer(1);
+	if (!xfer)
+		return -ENOMEM;
+
+	/* Fill ENTDAA CCC */
+	ccc_id = I3C_CCC_ENTDAA;
+	daa_cmd = &xfer->cmds[0];
+	daa_cmd->addr = I3C_BROADCAST_ADDR;
+	daa_cmd->rnw = false;
+	daa_cmd->tx_buf = &ccc_id;
+	daa_cmd->tx_len = 1;
+	daa_cmd->type = XI3C_SDR_MODE;
+	daa_cmd->tid = XI3C_SDR_TID;
+	daa_cmd->continued = true;
+
+	ret = xi3c_master_common_xfer(master, xfer);
+	/*
+	 * A NACK on the ENTDAA broadcast (I3C_ERROR_M2) means no slaves are
+	 * present to enter DAA. Treat as a successful no-op after letting
+	 * err_daa reinitialize the controller.
+	 */
+	if (ret && daa_cmd->err == I3C_ERROR_M2) {
+		ret = 0;
+		goto err_daa;
+	}
+	if (ret)
+		goto err_daa;
+
+	master->daa.index = 0;
+
+	while (true) {
+		struct xi3c_cmd *cmd = &xfer->cmds[0];
+		u8 daa_byte;
+
+		if (master->daa.index >= XI3C_MAX_DEVS) {
+			ret = -ENOSPC;
+			goto err_daa;
+		}
+
+		addr = i3c_master_get_free_addr(m, last_addr + 1);
+		if (addr < 0) {
+			ret = addr;
+			goto err_daa;
+		}
+
+		pid_buf = pid_bufs[master->daa.index];
+
+		daa_byte = (addr << 1) | (parity8(addr) ^ 1);
+
+		cmd->tx_buf = &daa_byte;
+		cmd->tx_len = 1;
+		cmd->addr = I3C_BROADCAST_ADDR;
+		cmd->rnw = true;
+		cmd->rx_buf = pid_buf;
+		cmd->rx_len = XI3C_DAA_SLAVEINFO_READ_BYTECOUNT;
+		cmd->is_daa = true;
+		cmd->type = XI3C_SDR_MODE;
+		cmd->tid = XI3C_SDR_TID;
+		cmd->continued = true;
+
+		ret = xi3c_master_common_xfer(master, xfer);
+
+		/*
+		 * End of enumeration: the next responder NACK'd the
+		 * dynamic-address grant, surfaced as -ENODEV.
+		 * xi3c_master_xfer() has already reset the FIFOs and
+		 * resumed the core for us; just exit the loop and
+		 * register the responders collected so far.
+		 */
+		if (ret == -ENODEV) {
+			ret = 0;
+			break;
+		}
+		if (ret)
+			goto err_daa;
+
+		master->daa.addrs[master->daa.index] = addr;
+		last_addr = addr;
+		master->daa.index++;
+	}
+
+	for (i = 0; i < master->daa.index; i++) {
+		u64 pid;
+
+		ret = i3c_master_add_i3c_dev_locked(m, master->daa.addrs[i]);
+		if (ret)
+			goto err_daa;
+
+		pid = FIELD_GET(XI3C_PID_MASK,
+				get_unaligned_be64(pid_bufs[i]));
+		dev_dbg(master->dev, "Client %d: PID: 0x%llx\n", i, pid);
+	}
+
+	return 0;
+
+err_daa:
+	xi3c_master_reinit(master);
+	return ret;
+}
+
+static bool
+xi3c_master_supports_ccc_cmd(struct i3c_master_controller *master,
+			     const struct i3c_ccc_cmd *cmd)
+{
+	if (cmd->ndests > 1)
+		return false;
+
+	switch (cmd->id) {
+	case I3C_CCC_ENEC(true):
+	case I3C_CCC_ENEC(false):
+	case I3C_CCC_DISEC(true):
+	case I3C_CCC_DISEC(false):
+	case I3C_CCC_ENTAS(0, true):
+	case I3C_CCC_ENTAS(0, false):
+	case I3C_CCC_RSTDAA(true):
+	case I3C_CCC_RSTDAA(false):
+	case I3C_CCC_ENTDAA:
+	case I3C_CCC_SETMWL(true):
+	case I3C_CCC_SETMWL(false):
+	case I3C_CCC_SETMRL(true):
+	case I3C_CCC_SETMRL(false):
+	case I3C_CCC_SETDASA:
+	case I3C_CCC_SETNEWDA:
+	case I3C_CCC_GETMWL:
+	case I3C_CCC_GETMRL:
+	case I3C_CCC_GETPID:
+	case I3C_CCC_GETBCR:
+	case I3C_CCC_GETDCR:
+	case I3C_CCC_GETSTATUS:
+	case I3C_CCC_GETMXDS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int xi3c_master_send_bdcast_ccc_cmd(struct xi3c_master *master,
+					   struct i3c_ccc_cmd *ccc)
+{
+	struct xi3c_xfer *xfer __free(kfree) = NULL;
+	u8 *buf __free(kfree) = NULL;
+	struct xi3c_cmd *cmd;
+	u16 xfer_len;
+	int ret;
+
+	if (ccc->dests[0].payload.len >= XI3C_MAXDATA_LENGTH)
+		return -EINVAL;
+
+	xfer_len = ccc->dests[0].payload.len + 1;
+
+	xfer = xi3c_master_alloc_xfer(1);
+	if (!xfer)
+		return -ENOMEM;
+
+	buf = kmalloc(xfer_len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	buf[0] = ccc->id;
+	memcpy(&buf[1], ccc->dests[0].payload.data, ccc->dests[0].payload.len);
+
+	cmd = &xfer->cmds[0];
+	cmd->addr = ccc->dests[0].addr;
+	cmd->rnw = ccc->rnw;
+	cmd->tx_buf = buf;
+	cmd->tx_len = xfer_len;
+	cmd->type = XI3C_SDR_MODE;
+	cmd->tid = XI3C_SDR_TID;
+	cmd->continued = false;
+
+	ret = xi3c_master_common_xfer(master, xfer);
+	ccc->err = cmd->err;
+
+	return ret;
+}
+
+static int xi3c_master_send_direct_ccc_cmd(struct xi3c_master *master,
+					   struct i3c_ccc_cmd *ccc)
+{
+	struct xi3c_xfer *xfer __free(kfree) = NULL;
+	struct xi3c_cmd *cmd;
+	int ret;
+
+	if (ccc->dests[0].payload.len > XI3C_MAXDATA_LENGTH)
+		return -EINVAL;
+
+	xfer = xi3c_master_alloc_xfer(2);
+	if (!xfer)
+		return -ENOMEM;
+
+	/* Broadcasted message */
+	cmd = &xfer->cmds[0];
+	cmd->addr = I3C_BROADCAST_ADDR;
+	cmd->rnw = false;
+	cmd->tx_buf = &ccc->id;
+	cmd->tx_len = 1;
+	cmd->type = XI3C_SDR_MODE;
+	cmd->tid = XI3C_SDR_TID;
+	cmd->continued = true;
+
+	/* Directed message */
+	cmd = &xfer->cmds[1];
+	cmd->addr = ccc->dests[0].addr;
+	cmd->rnw = ccc->rnw;
+	if (cmd->rnw) {
+		cmd->rx_buf = ccc->dests[0].payload.data;
+		cmd->rx_len = ccc->dests[0].payload.len;
+	} else {
+		cmd->tx_buf = ccc->dests[0].payload.data;
+		cmd->tx_len = ccc->dests[0].payload.len;
+	}
+	cmd->type = XI3C_SDR_MODE;
+	cmd->tid = XI3C_SDR_TID;
+	cmd->continued = false;
+
+	ret = xi3c_master_common_xfer(master, xfer);
+
+	/*
+	 * Report the broadcast command's error if it failed, otherwise the
+	 * directed command's, so a NACK on either phase reaches the caller.
+	 */
+	ccc->err = xfer->cmds[0].err ? xfer->cmds[0].err : xfer->cmds[1].err;
+
+	return ret;
+}
+
+static int xi3c_master_send_ccc_cmd(struct i3c_master_controller *m,
+				    struct i3c_ccc_cmd *cmd)
+{
+	struct xi3c_master *master = to_xi3c_master(m);
+
+	if (cmd->id & I3C_CCC_DIRECT)
+		return xi3c_master_send_direct_ccc_cmd(master, cmd);
+
+	return xi3c_master_send_bdcast_ccc_cmd(master, cmd);
+}
+
+static int xi3c_master_i3c_xfers(struct i3c_dev_desc *dev,
+				 struct i3c_xfer *xfers,
+				 int nxfers, enum i3c_xfer_mode mode)
+{
+	struct i3c_master_controller *m = i3c_dev_get_master(dev);
+	struct xi3c_master *master = to_xi3c_master(m);
+	struct xi3c_xfer *xfer __free(kfree) = NULL;
+	int i, ret;
+
+	if (!nxfers)
+		return 0;
+
+	if (mode != I3C_SDR)
+		return -EOPNOTSUPP;
+
+	for (i = 0; i < nxfers; i++)
+		if (xfers[i].len > XI3C_MAXDATA_LENGTH)
+			return -EINVAL;
+
+	xfer = xi3c_master_alloc_xfer(nxfers);
+	if (!xfer)
+		return -ENOMEM;
+
+	for (i = 0; i < nxfers; i++) {
+		struct xi3c_cmd *cmd = &xfer->cmds[i];
+
+		cmd->addr = dev->info.dyn_addr;
+		cmd->rnw = xfers[i].rnw;
+
+		if (cmd->rnw) {
+			cmd->rx_buf = xfers[i].data.in;
+			cmd->rx_len = xfers[i].len;
+		} else {
+			cmd->tx_buf = xfers[i].data.out;
+			cmd->tx_len = xfers[i].len;
+		}
+
+		cmd->type = XI3C_SDR_MODE;
+		cmd->tid = XI3C_SDR_TID;
+		cmd->continued = (i + 1) < nxfers;
+	}
+
+	ret = xi3c_master_common_xfer(master, xfer);
+
+	for (i = 0; i < nxfers; i++) {
+		xfers[i].err = xfer->cmds[i].err;
+		if (xfers[i].rnw)
+			xfers[i].actual_len = xfers[i].len - xfer->cmds[i].rx_len;
+	}
+
+	return ret;
+}
+
+static int xi3c_master_i2c_xfers(struct i2c_dev_desc *dev,
+				 struct i2c_msg *xfers,
+				 int nxfers)
+{
+	struct i3c_master_controller *m = i2c_dev_get_master(dev);
+	struct xi3c_master *master = to_xi3c_master(m);
+	struct xi3c_xfer *xfer __free(kfree) = NULL;
+	int i;
+
+	if (!nxfers)
+		return 0;
+
+	for (i = 0; i < nxfers; i++)
+		if (xfers[i].len > XI3C_MAXDATA_LENGTH)
+			return -EINVAL;
+
+	xfer = xi3c_master_alloc_xfer(nxfers);
+	if (!xfer)
+		return -ENOMEM;
+
+	for (i = 0; i < nxfers; i++) {
+		struct xi3c_cmd *cmd = &xfer->cmds[i];
+
+		cmd->addr = xfers[i].addr & XI3C_ADDR_MASK;
+		cmd->rnw = !!(xfers[i].flags & I2C_M_RD);
+
+		if (cmd->rnw) {
+			cmd->rx_buf = xfers[i].buf;
+			cmd->rx_len = xfers[i].len;
+		} else {
+			cmd->tx_buf = xfers[i].buf;
+			cmd->tx_len = xfers[i].len;
+		}
+
+		cmd->type = XI3C_I2C_MODE;
+		cmd->tid = XI3C_I2C_TID;
+		cmd->continued = (i + 1) < nxfers;
+	}
+
+	return xi3c_master_common_xfer(master, xfer);
+}
+
+static int xi3c_clk_cfg(struct xi3c_master *master, unsigned long sclhz, u8 mode)
+{
+	unsigned long core_rate, core_periodns;
+	u32 tcasmin, tsustart, tsustop, thdstart;
+	u32 thigh, tlow, thold;
+	u32 odthigh, odtlow;
+
+	core_rate = clk_get_rate(master->pclk);
+	if (!core_rate)
+		return -EINVAL;
+
+	if (!sclhz)
+		return -EINVAL;
+
+	core_periodns = DIV_ROUND_UP(NSEC_PER_SEC, core_rate);
+
+	thigh = DIV_ROUND_UP(core_rate, sclhz) >> 1;
+	tlow = thigh;
+
+	if (thigh <= XI3C_CYCLE_ADJUST)
+		return -EINVAL;
+
+	/* Hold time : 40% of tlow time */
+	thold = (tlow * 4) / 10;
+
+	if (xi3c_get_revision_number(master) == 0)
+		thold = max_t(u32, thold, XI3C_THOLD_MIN_REV0);
+	else
+		thold = max_t(u32, thold, XI3C_THOLD_MIN_REV1);
+
+	iowrite32((thigh - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
+		  master->membase + XI3C_SCL_HIGH_TIME_OFFSET);
+	iowrite32((tlow - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
+		  master->membase + XI3C_SCL_LOW_TIME_OFFSET);
+	iowrite32((thold - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
+		  master->membase + XI3C_SDA_HOLD_TIME_OFFSET);
+
+	if (mode == XI3C_I2C_MODE) {
+		iowrite32((thigh - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
+			  master->membase + XI3C_OD_SCL_HIGH_TIME_OFFSET);
+		iowrite32((tlow - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
+			  master->membase + XI3C_OD_SCL_LOW_TIME_OFFSET);
+
+		tcasmin = DIV_ROUND_UP(XI3C_I2C_TCASMIN_NS, core_periodns);
+	} else {
+		odtlow = DIV_ROUND_UP(XI3C_OD_TLOW_NS, core_periodns);
+		odthigh = DIV_ROUND_UP(XI3C_OD_THIGH_NS, core_periodns);
+
+		odtlow = max(tlow, odtlow);
+		odthigh = min(thigh, odthigh);
+
+		if (odthigh <= XI3C_CYCLE_ADJUST)
+			return -EINVAL;
+
+		iowrite32((odthigh - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
+			  master->membase + XI3C_OD_SCL_HIGH_TIME_OFFSET);
+		iowrite32((odtlow - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
+			  master->membase + XI3C_OD_SCL_LOW_TIME_OFFSET);
+
+		tcasmin = DIV_ROUND_UP(XI3C_TCASMIN_NS, core_periodns);
+	}
+
+	thdstart = max(thigh, tcasmin);
+	tsustart = max(tlow, tcasmin);
+	tsustop = max(tlow, tcasmin);
+
+	iowrite32((tsustart - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
+		  master->membase + XI3C_TSU_START_OFFSET);
+	iowrite32((thdstart - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
+		  master->membase + XI3C_THD_START_OFFSET);
+	iowrite32((tsustop - XI3C_CYCLE_ADJUST) & XI3C_TIMING_MASK,
+		  master->membase + XI3C_TSU_STOP_OFFSET);
+
+	return 0;
+}
+
+static int xi3c_master_bus_init(struct i3c_master_controller *m)
+{
+	struct xi3c_master *master = to_xi3c_master(m);
+	struct i3c_bus *bus = i3c_master_get_bus(m);
+	struct i3c_device_info info = {};
+	unsigned long sclhz;
+	u32 pid1_bcr_dcr;
+	u8 mode;
+	int ret;
+
+	switch (bus->mode) {
+	case I3C_BUS_MODE_MIXED_FAST:
+	case I3C_BUS_MODE_MIXED_LIMITED:
+	case I3C_BUS_MODE_MIXED_SLOW:
+		mode = XI3C_I2C_MODE;
+		sclhz = bus->scl_rate.i2c;
+		break;
+	case I3C_BUS_MODE_PURE:
+		mode = XI3C_SDR_MODE;
+		sclhz = bus->scl_rate.i3c;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = xi3c_clk_cfg(master, sclhz, mode);
+	if (ret)
+		return ret;
+
+	xi3c_master_init(master);
+
+	/* Get an address for the master. */
+	ret = i3c_master_get_free_addr(m, 0);
+	if (ret < 0)
+		return ret;
+
+	info.dyn_addr = ret;
+
+	/* Write the dynamic address value to the address register. */
+	iowrite32(info.dyn_addr, master->membase + XI3C_ADDRESS_OFFSET);
+
+	/* Read PID, BCR and DCR values, and assign to i3c device info. */
+	pid1_bcr_dcr = ioread32(master->membase + XI3C_PID1_BCR_DCR);
+	info.pid = ((u64)FIELD_GET(XI3C_PID1_MASK, pid1_bcr_dcr) << 32) |
+		   ioread32(master->membase + XI3C_PID0_OFFSET);
+	info.bcr = FIELD_GET(XI3C_BCR_MASK, pid1_bcr_dcr);
+	info.dcr = FIELD_GET(XI3C_DCR_MASK, pid1_bcr_dcr);
+
+	return i3c_master_set_info(&master->base, &info);
+}
+
+static void xi3c_master_bus_cleanup(struct i3c_master_controller *m)
+{
+	struct xi3c_master *master = to_xi3c_master(m);
+
+	xi3c_master_disable(master);
+}
+
+static const struct i3c_master_controller_ops xi3c_master_ops = {
+	.bus_init = xi3c_master_bus_init,
+	.bus_cleanup = xi3c_master_bus_cleanup,
+	.do_daa = xi3c_master_do_daa,
+	.supports_ccc_cmd = xi3c_master_supports_ccc_cmd,
+	.send_ccc_cmd = xi3c_master_send_ccc_cmd,
+	.i3c_xfers = xi3c_master_i3c_xfers,
+	.i2c_xfers = xi3c_master_i2c_xfers,
+};
+
+static int xi3c_master_probe(struct platform_device *pdev)
+{
+	struct xi3c_master *master;
+	int ret;
+
+	master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
+	if (!master)
+		return -ENOMEM;
+
+	master->dev = &pdev->dev;
+
+	master->membase = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(master->membase))
+		return dev_err_probe(master->dev, PTR_ERR(master->membase),
+				     "Failed to map registers\n");
+
+	master->pclk = devm_clk_get_enabled(master->dev, NULL);
+	if (IS_ERR(master->pclk))
+		return dev_err_probe(master->dev, PTR_ERR(master->pclk),
+				     "Failed to get and enable clock\n");
+
+	ret = devm_mutex_init(master->dev, &master->lock);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, master);
+
+	return i3c_master_register(&master->base, master->dev,
+				   &xi3c_master_ops, false);
+}
+
+static void xi3c_master_remove(struct platform_device *pdev)
+{
+	struct xi3c_master *master = platform_get_drvdata(pdev);
+
+	i3c_master_unregister(&master->base);
+}
+
+static const struct of_device_id xi3c_master_of_ids[] = {
+	{ .compatible = "xlnx,axi-i3c-1.0" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, xi3c_master_of_ids);
+
+static struct platform_driver xi3c_master_driver = {
+	.probe = xi3c_master_probe,
+	.remove = xi3c_master_remove,
+	.driver = {
+		.name = "axi-i3c-master",
+		.of_match_table = xi3c_master_of_ids,
+	},
+};
+module_platform_driver(xi3c_master_driver);
+
+MODULE_AUTHOR("Manikanta Guntupalli <manikanta.guntupalli@amd.com>");
+MODULE_AUTHOR("Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>");
+MODULE_AUTHOR("Shubham Patil <shubhamsanjay.patil@amd.com>");
+MODULE_DESCRIPTION("AMD AXI I3C master driver");
+MODULE_LICENSE("GPL");
-- 
2.34.1


^ permalink raw reply related

* [PATCH v9 1/2] dt-bindings: i3c: Add AMD I3C master controller support
From: Shubham Patil @ 2026-06-23 11:44 UTC (permalink / raw)
  To: git, michal.simek, alexandre.belloni, Frank.Li, robh, krzk+dt,
	conor+dt, pgaj, wsa+renesas, tommaso.merciai.xr, arnd,
	quic_msavaliy, Shyam-sundar.S-k, sakari.ailus, billy_tsai, kees,
	gustavoars, jarkko.nikula, jorge.marques, linux-i3c, devicetree,
	linux-kernel, linux-arch, linux-hardening
  Cc: radhey.shyam.pandey, srinivas.goud, shubhrajyoti.datta,
	shubhamsanjay.patil, Manikanta Guntupalli
In-Reply-To: <20260623114417.2578189-1-shubhamsanjay.patil@amd.com>

From: Manikanta Guntupalli <manikanta.guntupalli@amd.com>

Add device tree binding documentation for the AMD I3C master controller
version 1.0.

Signed-off-by: Manikanta Guntupalli <manikanta.guntupalli@amd.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
---
Changes for V9:
None.

Changes for V8:
None.

Changes for V7:
Added i3c controller version details to commit description.

Changes for V6:
Corrected the file name for $id in yaml to fix the dtschema warning.

Changes for V5:
Renamed the xlnx,axi-i3c.yaml file into xlnx,axi-i3c-1.0.yaml.

Changes for V4:
Added h/w documentation details.

Changes for V3:
Updated commit description.
Corrected the order of properties and removed resets property.
Added compatible to required list.
Added interrupts to example.

Changes for V2:
Updated commit subject and description.
Moved allOf to after required.
Removed xlnx,num-targets property.
---
 .../bindings/i3c/xlnx,axi-i3c-1.0.yaml        | 56 +++++++++++++++++++
 1 file changed, 56 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml

diff --git a/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml b/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
new file mode 100644
index 000000000000..75f677696f02
--- /dev/null
+++ b/Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/i3c/xlnx,axi-i3c-1.0.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: AMD I3C master
+
+maintainers:
+  - Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
+  - Shubham Patil <shubhamsanjay.patil@amd.com>
+
+description:
+  The AXI-I3C IP is an I3C Controller with an AXI4-Lite interface, compatible
+  with the MIPI I3C Specification v1.1.1. The design includes bidirectional I/O
+  buffers that implement open collector drivers for the SDA and SCL signals.
+  External pull-up resistors are required to properly hold the bus at a Logic-1
+  level when the drivers are released.
+
+  For more details, please see https://docs.amd.com/r/en-US/pg439-axi-i3c
+
+properties:
+  compatible:
+    const: xlnx,axi-i3c-1.0
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+
+allOf:
+  - $ref: i3c.yaml#
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    i3c@80000000 {
+        compatible = "xlnx,axi-i3c-1.0";
+        reg = <0x80000000 0x10000>;
+        clocks = <&zynqmp_clk 71>;
+        interrupt-parent = <&imux>;
+        interrupts = <0 89 4>;
+        #address-cells = <3>;
+        #size-cells = <0>;
+    };
+...
-- 
2.34.1


^ permalink raw reply related

* [PATCH v9 0/2] Add AMD I3C master controller driver and bindings
From: Shubham Patil @ 2026-06-23 11:44 UTC (permalink / raw)
  To: git, michal.simek, alexandre.belloni, Frank.Li, robh, krzk+dt,
	conor+dt, pgaj, wsa+renesas, tommaso.merciai.xr, arnd,
	quic_msavaliy, Shyam-sundar.S-k, sakari.ailus, billy_tsai, kees,
	gustavoars, jarkko.nikula, jorge.marques, linux-i3c, devicetree,
	linux-kernel, linux-arch, linux-hardening
  Cc: radhey.shyam.pandey, srinivas.goud, shubhrajyoti.datta,
	shubhamsanjay.patil

This patch series introduces support for the AMD I3C master controller,
including the device tree binding and driver implementation.

Compared to v8, the big-endian MMIO accessor and i3c FIFO-endianness
patches have been dropped; the driver now handles big-endian FIFO
accesses internally.

Note: There was an extended gap since v8 due to the transfer of ownership
of this series from Manikanta to Shubham. This transition contributed
to the delay in releasing the v9 update addressing the v8 review comments.
We appreciate your patience.
---
Changes for V9:
Dropped the three big-endian MMIO/FIFO infrastructure patches; the
driver now handles big-endian FIFO accesses internally.
Replaced the async transfer-queue with a synchronous transfer path.
Reworked error/response handling using enum i3c_error_code and proper
-ENODEV/-EIO returns; propagate err to CCCs and priv xfers.
Switched to the new .i3c_xfers op (reject non-SDR, report actual_len).
Reworked DAA (incremental address assignment, -ENOSPC bound, -ENODEV
end-of-enumeration, checked device registration).
Avoid busy-spin with usleep_range(); use FIELD_PREP() and inline
helpers; split the timeout macros with documented units.
Dropped ENTHDR (SDR-only); updated MAINTAINERS, Kconfig symbol
(AMD_AXI_I3C_MASTER), authors and binding maintainers.

Changes for V8:
Included dependent patch "i3c: fix big-endian FIFO transfers"
to this series as [3/5].
Resolved conflicts with "i3c: fix big-endian FIFO transfers".
Updated description.
Used time_left instead of timeout.
Used __free(kfree) for xfer to simplify err path in multiple places.

Changes for V7:
Added i3c controller version details to commit description.
Added Reviewed-by tag to binding patch [1/4].
Added big-endian MMIO accessors [2/4].
Added endianness support for i3c_readl_fifo() and i3c_writel_fifo() [3/4].
Updated timeout macro name.
Updated xi3c_master_wr_to_tx_fifo() and xi3c_master_rd_from_rx_fifo()
to use i3c_writel_fifo() and i3c_readl_fifo().

Changes for V6:
Corrected the $id in the YAML file to match the filename and fix
the dtschema warning.
Removed typecast for xi3c_getrevisionnumber(), xi3c_wrfifolevel(),
and xi3c_rdfifolevel().
Replaced dynamic allocation with a static variable for pid_bcr_dcr.
Fixed sparse warning in do_daa by typecasting the address parity value
to u8.
Fixed sparse warning in xi3c_master_bus_init by typecasting the pid value
to u64 in info.pid calculation.

Changes for V5:
Renamed the xlnx,axi-i3c.yaml file into xlnx,axi-i3c-1.0.yaml.
Used GENMASK_ULL for PID mask as it's 64bit mask.

Changes for V4:
Added h/w documentation details.
Updated timeout macros.
Removed type casting for xi3c_is_resp_available() macro.
Used ioread32() and iowrite32() instead of readl() and writel()
to keep consistency.
Read XI3C_RESET_OFFSET reg before udelay().
Removed xi3c_master_free_xfer() and directly used kfree().
Skipped checking return value of i3c_master_add_i3c_dev_locked().
Used devm_mutex_init() instead of mutex_init().

Changes for V3:
Updated commit description.
Corrected the order of properties and removed resets property.
Added compatible to required list.
Added interrupts to example.
Resolved merge conflicts.

Changes for V2:
Updated commit subject and description.
Moved allOf to after required.
Removed xlnx,num-targets property.
Added mixed mode support with clock configuration.
Converted smaller functions into inline functions.
Used FIELD_GET() in xi3c_get_response().
Updated xi3c_master_rd_from_rx_fifo() to use cmd->rx_buf.
Used parity8() for address parity calculation.
Added guards for locks.
Dropped num_targets and updated xi3c_master_do_daa().
Used __free(kfree) in xi3c_master_send_bdcast_ccc_cmd().
Dropped PM runtime support.
Updated xi3c_master_read() and xi3c_master_write() with
xi3c_is_resp_available() check.
Created separate functions: xi3c_master_init() and xi3c_master_reinit().
Used xi3c_master_init() in bus initialization and xi3c_master_reinit()
in error paths.
Added DAA structure to xi3c_master structure.
---
Manikanta Guntupalli (2):
  dt-bindings: i3c: Add AMD I3C master controller support
  i3c: master: Add driver for AMD AXI I3C master controller

 .../bindings/i3c/xlnx,axi-i3c-1.0.yaml        |   56 +
 MAINTAINERS                                   |    8 +
 drivers/i3c/master/Kconfig                    |   15 +
 drivers/i3c/master/Makefile                   |    1 +
 drivers/i3c/master/amd-i3c-master.c           | 1060 +++++++++++++++++
 5 files changed, 1140 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i3c/xlnx,axi-i3c-1.0.yaml
 create mode 100644 drivers/i3c/master/amd-i3c-master.c

-- 
2.34.1


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox